



  

Firebase Admin SDK for PHP Documentation

 [Firebase Admin SDK for PHP](index.html#document-index) 

 6.x

 

* [Overview](index.html#document-overview)

	+ [Requirements](index.html#requirements)

	+ [Installation](index.html#installation)

	+ [Usage examples](index.html#usage-examples)

	+ [Issues/Support](index.html#issues-support)

	+ [License](index.html#license)

	+ [Contributing](index.html#contributing)

		- [Guidelines](index.html#guidelines)

		- [Running the tests](index.html#running-the-tests)

		- [Coding standards](index.html#coding-standards)

* [Setup](index.html#document-setup)

	+ [Google Service Account](index.html#google-service-account)

		- [With autodiscovery](index.html#with-autodiscovery)

	+ [Project ID](index.html#project-id)

	+ [Realtime Database URI](index.html#realtime-database-uri)

	+ [Caching](index.html#caching)

		- [Authentication tokens](index.html#authentication-tokens)

		- [ID Token Verification](index.html#id-token-verification)

	+ [End User Credentials](index.html#end-user-credentials)

	+ [HTTP Client Options](index.html#http-client-options)

	+ [Logging](index.html#logging)

* [Cloud Messaging](index.html#document-cloud-messaging)

	+ [Initializing the Messaging component](index.html#initializing-the-messaging-component)

	+ [Getting started](index.html#getting-started)

	+ [Send messages to topics](index.html#send-messages-to-topics)

	+ [Send conditional messages](index.html#send-conditional-messages)

	+ [Send messages to specific devices](index.html#send-messages-to-specific-devices)

	+ [Send messages to multiple devices (Multicast)](index.html#send-messages-to-multiple-devices-multicast)

	+ [Send multiple messages at once](index.html#send-multiple-messages-at-once)

	+ [Adding a notification](index.html#adding-a-notification)

	+ [Adding data](index.html#adding-data)

	+ [Changing the message target](index.html#changing-the-message-target)

	+ [Adding target platform specific configuration](index.html#adding-target-platform-specific-configuration)

		- [Android](index.html#id2)

		- [APNs](index.html#apns)

		- [WebPush](index.html#webpush)

	+ [Adding platform independent FCM options](index.html#adding-platform-independent-fcm-options)

	+ [Notification Sounds](index.html#notification-sounds)

	+ [Message Priority](index.html#message-priority)

		- [Android](index.html#id3)

		- [iOS (APNS)](index.html#ios-apns)

		- [Web](index.html#id4)

		- [Combined](index.html#combined)

		- [Example](index.html#example)

	+ [Using Emojis](index.html#using-emojis)

	+ [Sending a fully configured raw message](index.html#sending-a-fully-configured-raw-message)

	+ [Validating messages](index.html#validating-messages)

	+ [Validating Registration Tokens](index.html#validating-registration-tokens)

	+ [Topic management](index.html#topic-management)

	+ [App instance management](index.html#app-instance-management)

		- [Working with topic subscriptions](index.html#working-with-topic-subscriptions)

* [Cloud Firestore](index.html#document-cloud-firestore)

	+ [Initializing the Firestore component](index.html#initializing-the-firestore-component)

	+ [Getting started](index.html#getting-started)

* [Cloud Storage](index.html#document-cloud-storage)

	+ [Initializing the Storage component](index.html#initializing-the-storage-component)

	+ [Getting started](index.html#getting-started)

	+ [Default Storage bucket](index.html#default-storage-bucket)

* [Realtime Database](index.html#document-realtime-database)

	+ [Initializing the Realtime Database component](index.html#initializing-the-realtime-database-component)

	+ [Retrieving data](index.html#retrieving-data)

		- [Database Snapshots](index.html#database-snapshots)

		- [Queries](index.html#queries)

		- [Shallow queries](index.html#shallow-queries)

		- [Ordering data](index.html#ordering-data)

		- [Filtering data](index.html#filtering-data)

	+ [Saving data](index.html#saving-data)

		- [Set/replace values](index.html#set-replace-values)

		- [Update specific fields](index.html#update-specific-fields)

		- [Writing lists](index.html#writing-lists)

		- [Server values](index.html#server-values)

		- [Delete data](index.html#delete-data)

	+ [Database transactions](index.html#database-transactions)

		- [Replace data inside a transaction](index.html#replace-data-inside-a-transaction)

		- [Delete data inside a transaction](index.html#delete-data-inside-a-transaction)

		- [Handling transaction failures](index.html#handling-transaction-failures)

	+ [Debugging API exceptions](index.html#debugging-api-exceptions)

	+ [Database rules](index.html#database-rules)

	+ [Authenticate with limited privileges](index.html#authenticate-with-limited-privileges)

* [Authentication](index.html#document-authentication)

	+ [Initializing the Auth component](index.html#initializing-the-auth-component)

	+ [Create custom tokens](index.html#id2)

	+ [Verify a Firebase ID Token](index.html#verify-a-firebase-id-token)

	+ [Custom Authentication Flows](index.html#custom-authentication-flows)

		- [Anonymous Sign In](index.html#anonymous-sign-in)

		- [Sign In with Email and Password](index.html#sign-in-with-email-and-password)

		- [Sign In with Email and Oob Code](index.html#sign-in-with-email-and-oob-code)

		- [Sign In with a Custom Token](index.html#sign-in-with-a-custom-token)

		- [Sign In with a Refresh Token](index.html#sign-in-with-a-refresh-token)

		- [Sign In with IdP credentials](index.html#sign-in-with-idp-credentials)

		- [Sign In without a token](index.html#sign-in-without-a-token)

		- [Linking and Unlinking Identity Providers](index.html#linking-and-unlinking-identity-providers)

	+ [Invalidate user sessions](index.html#invalidate-user-sessions)

	+ [Session Cookies](index.html#session-cookies)

		- [Create session cookie](index.html#create-session-cookie)

		- [Verify a Firebase Session Cookie](index.html#verify-a-firebase-session-cookie)

	+ [Tenant Awareness](index.html#tenant-awareness)

* [User management](index.html#document-user-management)

	+ [User Records](index.html#user-records)

	+ [List users](index.html#list-users)

	+ [Query users](index.html#query-users)

	+ [Get information about a specific user](index.html#get-information-about-a-specific-user)

	+ [Get information about multiple users](index.html#get-information-about-multiple-users)

	+ [Create a user](index.html#create-a-user)

	+ [Update a user](index.html#update-a-user)

	+ [Change a user’s password](index.html#change-a-user-s-password)

	+ [Change a user’s email](index.html#change-a-user-s-email)

	+ [Disable a user](index.html#disable-a-user)

	+ [Enable a user](index.html#enable-a-user)

	+ [Custom user claims](index.html#custom-user-claims)

	+ [Delete a user](index.html#delete-a-user)

	+ [Delete multiple users](index.html#delete-multiple-users)

	+ [Using Email Action Codes](index.html#using-email-action-codes)

		- [Action Code Settings](index.html#action-code-settings)

		- [Email verification](index.html#email-verification)

		- [Password reset](index.html#password-reset)

		- [Email link for sign-in](index.html#email-link-for-sign-in)

		- [Confirm a password reset](index.html#confirm-a-password-reset)

* [Dynamic Links](index.html#document-dynamic-links)

	+ [Getting started](index.html#getting-started)

	+ [Initializing the Dynamic Links component](index.html#initializing-the-dynamic-links-component)

	+ [Create a Dynamic Link](index.html#create-a-dynamic-link)

	+ [Create a short link from a long link](index.html#create-a-short-link-from-a-long-link)

	+ [Get link statistics](index.html#get-link-statistics)

		- [Event Statistics](index.html#event-statistics)

	+ [Advanced usage](index.html#advanced-usage)

		- [Using actions](index.html#using-actions)

		- [Using parameter arrays](index.html#using-parameter-arrays)

* [Remote Config](index.html#document-remote-config)

	+ [Before you begin](index.html#before-you-begin)

	+ [Initializing the Realtime Database component](index.html#initializing-the-realtime-database-component)

	+ [Get the Remote Config](index.html#get-the-remote-config)

	+ [Create a new Remote Config](index.html#create-a-new-remote-config)

	+ [Add a condition](index.html#add-a-condition)

	+ [Add a parameter](index.html#add-a-parameter)

	+ [Conditional values](index.html#conditional-values)

	+ [Parameter Groups](index.html#parameter-groups)

	+ [Removing Remote Config Elements](index.html#removing-remote-config-elements)

	+ [Validation](index.html#validation)

	+ [Publish the Remote Config](index.html#publish-the-remote-config)

	+ [Remote Config history](index.html#remote-config-history)

		- [List versions](index.html#list-versions)

		- [Filtering](index.html#filtering)

		- [Get a specific version](index.html#get-a-specific-version)

		- [Rollback to a version](index.html#rollback-to-a-version)

* [Framework Integrations](index.html#document-framework-integrations)

	+ [Laravel](index.html#laravel)

	+ [Symfony](index.html#symfony)

	+ [CodeIgniter](index.html#codeigniter)

* [Testing and Local Development](index.html#document-testing)

	+ [Integration Tests](index.html#integration-tests)

	+ [Using the Firebase Emulator Suite](index.html#using-the-firebase-emulator-suite)

		- [Auth Emulator](index.html#auth-emulator)

		- [Realtime Database Emulator](index.html#realtime-database-emulator)

* [Tutorials](index.html#document-tutorials)

	+ [Articles](index.html#articles)

	+ [Videos](index.html#videos)

* [Troubleshooting](index.html#document-troubleshooting)

	+ [Error handling](index.html#error-handling)

	+ [Call to private/undefined method …](index.html#call-to-private-undefined-method)

	+ [PHP Parse Error/PHP Syntax Error](index.html#php-parse-error-php-syntax-error)

	+ [Class ‘Kreait\Firebase\ …’ not found](index.html#class-kreait-firebase-not-found)

	+ [Call to undefined function `openssl\_sign()`](index.html#call-to-undefined-function-openssl-sign)

	+ [Default sound not played on message delivery](index.html#default-sound-not-played-on-message-delivery)

	+ [cURL error XX: …](index.html#curl-error-xx)

	+ [“403 Forbidden” Errors](index.html#forbidden-errors)

	+ [MultiCast SendReports are empty](index.html#multicast-sendreports-are-empty)

	+ [Proxy configuration](index.html#proxy-configuration)

	+ [Debugging](index.html#debugging)

[Firebase Admin SDK for PHP](index.html#document-index)

* [Docs](index.html#document-index) »

* Firebase Admin SDK for PHP Documentation

* [Edit on GitHub](https://github.com/kreait/firebase-php/blob/6.x/docs/index.rst)

---

Firebase Admin SDK for PHP[¶](#firebase-admin-sdk-for-php "Permalink to this headline")

=======================================================================================

Interact with [Google Firebase](https://firebase.google.com) from your PHP application.

[![License](https://img.shields.io/github/license/kreait/firebase-php.svg)](https://github.com/kreait/firebase-php/blob/master/LICENSE)

[![Stargazers](https://img.shields.io/github/stars/kreait/firebase-php.svg)](https://github.com/kreait/firebase-php/stargazers)

[![Total downloads](https://img.shields.io/packagist/dt/kreait/firebase-php.svg)](https://packagist.org/packages/kreait/firebase-php)

[![Sponsoring](https://img.shields.io/static/v1?logo=GitHub&label=Sponsor&message=%E2%9D%A4&color=ff69b4)](https://github.com/sponsors/jeromegamez)

Note

If you are interested in using the PHP Admin SDK as a client for end-user access

(for example, in a web application), as opposed to admin access from a

privileged environment (like a server), you should instead follow the

[instructions for setting up the client JavaScript SDK](https://firebase.google.com/docs/web/setup).

The source code can be found at <https://github.com/kreait/firebase-php/> .

Quick Start[¶](#quick-start "Permalink to this headline")

---------------------------------------------------------

```

use Kreait\Firebase\Factory;

$factory = (new Factory)

    ->withServiceAccount('/path/to/firebase\_credentials.json')

    ->withDatabaseUri('https://my-project-default-rtdb.firebaseio.com');

$auth = $factory->createAuth();

$realtimeDatabase = $factory->createDatabase();

$cloudMessaging = $factory->createMessaging();

$remoteConfig = $factory->createRemoteConfig();

$cloudStorage = $factory->createStorage();

$firestore = $factory->createFirestore();

```

User Guide[¶](#user-guide "Permalink to this headline")

-------------------------------------------------------

### Overview[¶](#overview "Permalink to this headline")

#### Requirements[¶](#requirements "Permalink to this headline")

* PHP >= 7.4

* The [mbstring PHP extension](http://php.net/manual/en/book.mbstring.php)

* A Firebase project - create a new project in the [Firebase console](https://firebase.google.com/console/),

if you don’t already have one.

* A Google service account, follow the instructions in the

[official Firebase Server documentation](https://firebase.google.com/docs/server/setup#add_firebase_to_your_app)

and place the JSON configuration file somewhere in your project’s path.

#### Installation[¶](#installation "Permalink to this headline")

The recommended way to install the Firebase Admin SDK is with

[Composer](http://getcomposer.org). Composer is a dependency management tool

for PHP that allows you to declare the dependencies your project needs and

installs them into your project.

If you want to use the SDK within a Framework, please follow the installation instructions here:

* **Laravel**: [kreait/laravel-firebase](https://github.com/kreait/laravel-firebase)

* **Symfony**: [kreait/firebase-bundle](https://github.com/kreait/firebase-bundle)

```

composer require kreait/firebase-php

```

After installing, you need to require Composer’s autoloader:

```

<?php

require \_\_DIR\_\_.'/vendor/autoload.php';

```

You can find out more on how to install Composer, configure autoloading, and

other best-practices for defining dependencies at

[getcomposer.org](http://getcomposer.org).

Please continue to the [Setup section](index.html#setup) to learn more about connecting your application to Firebase.

#### Usage examples[¶](#usage-examples "Permalink to this headline")

You can find usage examples at

<https://github.com/jeromegamez/firebase-php-examples>

and in the [tests directory](https://github.com/kreait/firebase-php/tree/master/tests)

of this project’s [GitHub repository](https://github.com/kreait/firebase-php/).

#### Issues/Support[¶](#issues-support "Permalink to this headline")

* For bugs and past issues: [Github issue tracker](https://github.com/kreait/firebase-php/issues/)

* For questions about Firebase in general: [Stack Overflow](https://stackoverflow.com/questions/tagged/firebase) and the [Firebase Slack Community](https://firebase.community).

#### License[¶](#license "Permalink to this headline")

Licensed using the [MIT license](http://opensource.org/licenses/MIT).

> 

> Copyright (c) Jérôme Gamez <<https://github.com/jeromegamez>> <[jerome@gamez.name](mailto:jerome%40gamez.name)>

> 

> 

> Permission is hereby granted, free of charge, to any person obtaining a copy

> of this software and associated documentation files (the “Software”), to deal

> in the Software without restriction, including without limitation the rights

> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

> copies of the Software, and to permit persons to whom the Software is

> furnished to do so, subject to the following conditions:

> 

> 

> The above copyright notice and this permission notice shall be included in

> all copies or substantial portions of the Software.

> 

> 

> THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

> THE SOFTWARE.

> 

> 

> 

#### Contributing[¶](#contributing "Permalink to this headline")

##### Guidelines[¶](#guidelines "Permalink to this headline")

1. The SDK utilizes PSR-4, PSR-7 and PSR-12.

2. This SDK has a minimum PHP version requirement of PHP 7.4.

3. All pull requests should include unit tests to ensure the change works as

expected and to prevent regressions.

##### Running the tests[¶](#running-the-tests "Permalink to this headline")

The SDK is unit tested with PHPUnit. Run the tests using the Makefile:

```

make tests

```

##### Coding standards[¶](#coding-standards "Permalink to this headline")

The SDK uses the [PHP Coding Standards Fixer](https://github.com/FriendsOfPHP/PHP-CS-Fixer)

to ensure a uniform coding style. Apply coding standard fixed using the Makefile:

```

make cs

```

from the root of the project.

### Setup[¶](#setup "Permalink to this headline")

#### Google Service Account[¶](#google-service-account "Permalink to this headline")

In order to access a Firebase project using a server SDK, you must authenticate your requests to Firebase with

[Service Account credentials](https://developers.google.com/identity/protocols/OAuth2ServiceAccount).

To authenticate a service account and authorize it to access Firebase services, you must generate a private

key file in JSON format.

To generate a private key file for your service account:

1. Open <https://console.firebase.google.com/project/_/settings/serviceaccounts/adminsdk> and select

the project you want to generate a private key file for.

2. Click **Generate New Private Key**, then confirm by clicking **Generate Key**

3. Securely store the JSON file containing the key.

Note

You should store the JSON file outside of your code repository to avoid accidentally exposing it

to the outside world.

You can then configure the SDK to use this Service Account:

**With the SDK**

```

use Kreait\Firebase\Factory;

$factory = (new Factory)->withServiceAccount('/path/to/firebase\_credentials.json');

```

**With the** [Symfony Bundle](https://github.com/kreait/firebase-bundle)

Please see <https://github.com/kreait/firebase-bundle#configuration>

**With the** [Laravel/Lumen Package](https://github.com/kreait/laravel-firebase)

Please see <https://github.com/kreait/laravel-firebase#configuration>

##### With autodiscovery[¶](#with-autodiscovery "Permalink to this headline")

The SDK is able to auto-discover the Service Account for your project in the following conditions:

1. Your application runs on Google Cloud Engine.

2. The path to the JSON key file is defined in one of the following environment variables

	* `GOOGLE\_APPLICATION\_CREDENTIALS`

3. The JSON Key file is located in Google’s “well known path”

	* on Linux/MacOS: `$HOME/.config/gcloud/application\_default\_credentials.json`

	* on Windows: `$APPDATA/gcloud/application\_default\_credentials.json`

If you want to use autodiscovery, a Service Account must not be explicitly configured.

#### Project ID[¶](#project-id "Permalink to this headline")

Service Account credentials include the ID of the Google Cloud Project your Firebase project belongs to.

If you use another type of credential, it might be necessary to provide it manually to the Firebase Factory.

```

use Kreait\Firebase\Factory;

$factory = (new Factory())

    ->withProjectId('my-project')

    ->withDatabaseUri('https://my-project.firebaseio.com');

```

You can also set a `GOOGLE\_CLOUD\_PROJECT=<project-id>` environment variable before calling the factory.

#### Realtime Database URI[¶](#realtime-database-uri "Permalink to this headline")

Note

You can find the URI for your Realtime Database at

<https://console.firebase.google.com/project/_/database>.

For recently created Firebase projects the default database URI usually has the format

`https://<project-id>-default-rtdb.firebaseio.com`. Databases in projects created before September 2020 had the

default database URI `https://<project-id>.firebaseio.com`.

For backward compatibility reasons, if you don’t specify a database URI, the SDK will use the project ID defined

in the Service Account JSON file to automatically generate it.

```

use Kreait\Firebase\Factory;

$factory = (new Factory())

    ->withDatabaseUri('https://my-project.firebaseio.com');

```

#### Caching[¶](#caching "Permalink to this headline")

##### Authentication tokens[¶](#authentication-tokens "Permalink to this headline")

Before connecting to the Firebase APIs, the SDK fetches an authentication token for your credentials.

This authentication token is cached in-memory so that it can be re-used during the same process.

If you want to cache authentication tokens more effectively, you can provide any

[implementation of psr/cache](https://packagist.org/providers/psr/cache-implementation) to the

Firebase factory when creating your Firebase instance.

Note

Authentication tokens are cached in-memory by default. For Symfony and Laravel,

the Framework’s cache will automatically be used.

For Symfony and Laravel, the Framework’s cache will automatically be used.

Here is an example using the [Symfony Cache Component](https://symfony.com/doc/current/components/cache.html):

```

use Symfony\Component\Cache\Simple\FilesystemCache;

$factory = $factory->withAuthTokenCache(new FilesystemCache());

```

##### ID Token Verification[¶](#id-token-verification "Permalink to this headline")

In order to verify ID tokens, the verifier makes a call to fetch Firebase’s currently available public keys.

The keys are cached in memory by default.

If you want to cache the public keys more effectively, you can provide any

[implementation of psr/simple-cache](https://packagist.org/providers/psr/simple-cache-implementation) to the

Firebase factory when creating your Firebase instance.

Note

Public keys tokens are cached in-memory by default. For Symfony and Laravel,

the Framework’s cache will automatically be used.

Here is an example using the [Symfony Cache Component](https://symfony.com/doc/current/components/cache.html):

```

use Symfony\Component\Cache\Simple\FilesystemCache;

$factory = $factory->withVerifierCache(new FilesystemCache());

```

#### End User Credentials[¶](#end-user-credentials "Permalink to this headline")

Note

While theoretically possible, it’s not recommended to use end user credentials in the context

of a Server-to-Server backend application.

When using End User Credentials (for example if you set you application default credentials locally

with `gcloud auth application-default login`), you need to provide the ID of the project you

want to access directly and suppress warnings triggered by the Google Auth Component:

```

use Kreait\Firebase\Factory;

putenv('SUPPRESS\_GCLOUD\_CREDS\_WARNING=true');

// This will use the project defined in the Service Account

// credentials files by default

$base = (new Factory())->withProjectId('firebase-project-id');

```

#### HTTP Client Options[¶](#http-client-options "Permalink to this headline")

You can configure the behavior of the HTTP Client performing the API requests by passing an

instance of KreaitFirebaseHttpHttpClientOptions to the factory before creating a

service.

```

use Kreait\Firebase\Http\HttpClientOptions;

$options = HttpClientOptions::default();

// Set the maximum amount of seconds (float) that can pass before

// a request is considered timed out

// (default: indefinitely)

$options = $options->withTimeOut(3.5);

// Use a proxy that all API requests should be passed through.

// (default: none)

$options = $options->withProxy('tcp://<host>:<port>');

$factory = $factory->withHttpClientOptions($options);

// Newly created services will now use the new HTTP options

$realtimeDatabase = $factory->createDatabase();

```

#### Logging[¶](#logging "Permalink to this headline")

In order to log API requests to the Firebase APIs, you can provide the factory with loggers

implementing `Psr\Log\LoggerInterface`.

The following examples use the [Monolog](https://github.com/Seldaek/monolog) logger, but

work with any [PSR-3 log implementation](https://packagist.org/providers/psr/log-implementation).

```

use GuzzleHttp\MessageFormatter;

use Kreait\Firebase\Factory;

use Monolog\Logger;

use Monolog\Handler\StreamHandler;

$httpLogger = new Logger('firebase\_http\_logs');

$httpLogger->pushHandler(new StreamHandler('path/to/firebase\_api.log', Logger::INFO));

// Without further arguments, requests and responses will be logged with basic

// request and response information. Successful responses will be logged with

// the 'info' log level, failures (Status code >= 400) with 'notice'

$factory = $factory->withHttpLogger($httpLogger);

// You can configure the message format and log levels individually

$messageFormatter = new MessageFormatter(MessageFormatter::SHORT);

$factory = $factory->withHttpLogger(

    $httpLogger, $messageFormatter, $successes = 'debug', $errors = 'warning'

);

// You can provide a separate logger for detailed HTTP message logs

$httpDebugLogger = new Logger('firebase\_http\_debug\_logs');

$httpDebugLogger->pushHandler(

    new StreamHandler('path/to/firebase\_api\_debug.log',

    Logger::DEBUG)

);

// Logs will include the full request and response headers and bodies

$factory = $factory->withHttpDebugLogger($httpDebugLogger)

```

### Cloud Messaging[¶](#cloud-messaging "Permalink to this headline")

You can use the Firebase Admin SDK for PHP to send Firebase Cloud Messaging messages to end-user devices. Specifically, you can send messages to individual devices, named topics, or condition statements that match one or more topics.

Note

Sending messages to Device Groups is only possible with legacy protocols which are not supported

by this SDK.

Before you start, please read about Firebase Remote Config in the official documentation:

* [Introduction to Firebase Cloud Messaging](https://firebase.google.com/docs/cloud-messaging/)

* [Introduction to Admin FCM API](https://firebase.google.com/docs/cloud-messaging/admin/)

#### Initializing the Messaging component[¶](#initializing-the-messaging-component "Permalink to this headline")

**With the SDK**

```

$messaging = $factory->createMessaging();

```

**With Dependency Injection** ([Symfony Bundle](https://github.com/kreait/firebase-bundle)/[Laravel/Lumen Package](https://github.com/kreait/laravel-firebase))

```

use Kreait\Firebase\Contract\Messaging;

class MyService

{

    public function \_\_construct(Messaging $messaging)

    {

        $this->messaging = $messaging;

    }

}

```

**With the Laravel** `app()` **helper** ([Laravel/Lumen Package](https://github.com/kreait/laravel-firebase))

```

$messaging = app('firebase.messaging');

```

#### Getting started[¶](#getting-started "Permalink to this headline")

```

use Kreait\Firebase\Messaging\CloudMessage;

$message = CloudMessage::withTarget(/\* see sections below \*/)

    ->withNotification(Notification::create('Title', 'Body'))

    ->withData(['key' => 'value']);

$messaging->send($message);

```

A message must be an object implementing `Kreait\Firebase\Messaging\Message` or an array that can

be parsed to a `Kreait\Firebase\Messaging\CloudMessage`.

You can use `Kreait\Firebase\Messaging\RawMessageFromArray` to create a message without the SDK checking it

for validity before sending it. This gives you full control over the sent message, but also means that you

have to send/validate a message in order to know if it’s valid or not.

Note

If you notice that a field is not supported by the SDK yet, please open an issue on the issue tracker, so that others

can benefit from it as well.

#### Send messages to topics[¶](#send-messages-to-topics "Permalink to this headline")

Based on the publish/subscribe model, FCM topic messaging allows you to send a message to multiple devices that have opted in to a particular topic. You compose topic messages as needed, and FCM handles routing and delivering the message reliably to the right devices.

For example, users of a local weather forecasting app could opt in to a “severe weather alerts” topic and receive notifications of storms threatening specified areas. Users of a sports app could subscribe to automatic updates in live game scores for their favorite teams.

Some things to keep in mind about topics:

* Topic messaging supports unlimited topics and subscriptions for each app.

* Topic messaging is best suited for content such as news, weather, or other publicly available information.

* Topic messages are optimized for throughput rather than latency. For fast, secure delivery to single devices or small groups of devices, target messages to registration tokens, not topics.

You can create a message to a topic in one of the following ways:

```

use Kreait\Firebase\Messaging\CloudMessage;

$topic = 'a-topic';

$message = CloudMessage::withTarget('topic', $topic)

    ->withNotification($notification) // optional

    ->withData($data) // optional

;

$message = CloudMessage::fromArray([

    'topic' => $topic,

    'notification' => [/\* Notification data as array \*/], // optional

    'data' => [/\* data array \*/], // optional

]);

$messaging->send($message);

```

#### Send conditional messages[¶](#send-conditional-messages "Permalink to this headline")

Warning

OR-conditions are currently not processed correctly by the Firebase Rest API, leading to undelivered messages.

This can be resolved by splitting up a message to an OR-condition into multiple messages to AND-conditions.

So one conditional message to `'a' in topics || 'b' in topics` should be sent as two messages

to the conditions `'a' in topics && !('b' in topics)` and `'b' in topics && !('a' in topics)`

References:

* <https://github.com/firebase/quickstart-js/issues/183>

* <https://stackoverflow.com/a/52302136/284325>

Sometimes you want to send a message to a combination of topics. This is done by specifying a condition, which is a boolean expression that specifies the target topics. For example, the following condition will send messages to devices that are subscribed to `TopicA` and either `TopicB` or `TopicC`:

`"'TopicA' in topics && ('TopicB' in topics || 'TopicC' in topics)"`

FCM first evaluates any conditions in parentheses, and then evaluates the expression from left to right. In the above expression, a user subscribed to any single topic does not receive the message. Likewise, a user who does not subscribe to TopicA does not receive the message. These combinations do receive it:

* `TopicA` and `TopicB`

* `TopicA` and `TopicC`

```

use Kreait\Firebase\Messaging\CloudMessage;

$condition = "'TopicA' in topics && ('TopicB' in topics || 'TopicC' in topics)";

$message = CloudMessage::withTarget('condition', $condition)

    ->withNotification($notification) // optional

    ->withData($data) // optional

;

$message = CloudMessage::fromArray([

    'condition' => $condition,

    'notification' => [/\* Notification data as array \*/], // optional

    'data' => [/\* data array \*/], // optional

]);

$messaging->send($message);

```

#### Send messages to specific devices[¶](#send-messages-to-specific-devices "Permalink to this headline")

The Admin FCM API allows you to send messages to individual devices by specifying a registration token for the target device. Registration tokens are strings generated by the client FCM SDKs for each end-user client app instance.

Each of the Firebase client SDKs are able to generate these registration tokens: [iOS](https://firebase.google.com/docs/cloud-messaging/ios/client#access_the_registration_token), [Android](https://firebase.google.com/docs/cloud-messaging/android/client#sample-register), [Web](https://firebase.google.com/docs/cloud-messaging/js/client#access_the_registration_token), [C++](https://firebase.google.com/docs/cloud-messaging/cpp/client#access_the_device_registration_token), and [Unity](https://firebase.google.com/docs/cloud-messaging/unity/client#initialize_firebase_messaging).

```

use Kreait\Firebase\Messaging\CloudMessage;

$deviceToken = '...';

$message = CloudMessage::withTarget('token', $deviceToken)

    ->withNotification($notification) // optional

    ->withData($data) // optional

;

$message = CloudMessage::fromArray([

    'token' => $deviceToken,

    'notification' => [/\* Notification data as array \*/], // optional

    'data' => [/\* data array \*/], // optional

]);

$messaging->send($message);

```

#### Send messages to multiple devices (Multicast)[¶](#send-messages-to-multiple-devices-multicast "Permalink to this headline")

You can send one message to up to 500 devices:

```

use Kreait\Firebase\Messaging\CloudMessage;

$deviceTokens = ['...', '...' /\* ... \*/];

$message = CloudMessage::new(); // Any instance of Kreait\Messaging\Message

$sendReport = $messaging->sendMulticast($message, $deviceTokens);

```

The returned value is an instance of `Kreait\Firebase\Messaging\MulticastSendReport` and provides you with

methods to determine the successes and failures of the multicasted message:

```

$report = $messaging->sendMulticast($message, $deviceTokens);

echo 'Successful sends: '.$report->successes()->count().PHP\_EOL;

echo 'Failed sends: '.$report->failures()->count().PHP\_EOL;

if ($report->hasFailures()) {

    foreach ($report->failures()->getItems() as $failure) {

        echo $failure->error()->getMessage().PHP\_EOL;

    }

}

// The following methods return arrays with registration token strings

$successfulTargets = $report->validTokens(); // string[]

// Unknown tokens are tokens that are valid but not know to the currently

// used Firebase project. This can, for example, happen when you are

// sending from a project on a staging environment to tokens in a

// production environment

$unknownTargets = $report->unknownTokens(); // string[]

// Invalid (=malformed) tokens

$invalidTargets = $report->invalidTokens(); // string[]

```

#### Send multiple messages at once[¶](#send-multiple-messages-at-once "Permalink to this headline")

You can send up to 500 prepared messages (each message has a token, topic or condition as a target) in one go:

```

use Kreait\Firebase\Messaging\CloudMessage;

$messages = [

    // Up to 500 items, either objects implementing Kreait\Firebase\Messaging\Message

    // or arrays that can be used to create valid to Kreait\Firebase\Messaging\Cloudmessage instances

];

$message = CloudMessage::new(); // Any instance of Kreait\Messaging\Message

/\*\* @var Kreait\Firebase\Messaging\MulticastSendReport $sendReport \*\*/

$sendReport = $messaging->sendAll($messages);

```

#### Adding a notification[¶](#adding-a-notification "Permalink to this headline")

A notification is an instance of `Kreait\Firebase\Messaging\Notification` and can be

created in one of the following ways. The title and the body of a notification

are both optional.

```

use Kreait\Firebase\Messaging\Notification;

$title = 'My Notification Title';

$body = 'My Notification Body';

$imageUrl = 'http://lorempixel.com/400/200/';

$notification = Notification::fromArray([

    'title' => $title,

    'body' => $body,

    'image' => $imageUrl,

]);

$notification = Notification::create($title, $body);

$changedNotification = $notification

    ->withTitle('Changed title')

    ->withBody('Changed body')

    ->withImageUrl('http://lorempixel.com/200/400/');

```

Once you have created a message with one of the methods described below,

you can attach the notification to it:

```

$message = $message->withNotification($notification);

```

#### Adding data[¶](#adding-data "Permalink to this headline")

The data attached to a message must be an array of key-value pairs

where all keys and values are strings.

Once you have created a message with one of the methods described below,

you can attach data to it:

```

$data = [

    'first\_key' => 'First Value',

    'second\_key' => 'Second Value',

];

$message = $message->withData($data);

```

#### Changing the message target[¶](#changing-the-message-target "Permalink to this headline")

You can change the target of an already created message with the `withChangedTarget()` method.

```

use Kreait\Firebase\Messaging\CloudMessage;

$deviceToken = '...';

$anotherDeviceToken = '...';

$message = CloudMessage::withTarget('token', $deviceToken)

    ->withNotification(['title' => 'My title', 'body' => 'My Body'])

;

$messaging->send($message);

$sameMessageToDifferentTarget = $message->withChangedTarget('token', $anotherDeviceToken);

```

#### Adding target platform specific configuration[¶](#adding-target-platform-specific-configuration "Permalink to this headline")

You can target platforms specific configuration to your messages.

##### Android[¶](#id2 "Permalink to this headline")

You can find the full Android configuration reference in the official documentation:

[REST Resource: projects.messages.AndroidConfig](https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages#androidconfig)

```

use Kreait\Firebase\Messaging\AndroidConfig;

// Example from https://firebase.google.com/docs/cloud-messaging/admin/send-messages#android\_specific\_fields

$config = AndroidConfig::fromArray([

    'ttl' => '3600s',

    'priority' => 'normal',

    'notification' => [

        'title' => '$GOOG up 1.43% on the day',

        'body' => '$GOOG gained 11.80 points to close at 835.67, up 1.43% on the day.',

        'icon' => 'stock\_ticker\_update',

        'color' => '#f45342',

        'sound' => 'default',

    ],

]);

$message = $message->withAndroidConfig($config);

```

##### APNs[¶](#apns "Permalink to this headline")

You can find the full APNs configuration reference in the official documentation:

[REST Resource: projects.messages.ApnsConfig](https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages#apnsconfig)

```

use Kreait\Firebase\Messaging\ApnsConfig;

// Example from https://firebase.google.com/docs/cloud-messaging/admin/send-messages#apns\_specific\_fields

$config = ApnsConfig::fromArray([

    'headers' => [

        'apns-priority' => '10',

    ],

    'payload' => [

        'aps' => [

            'alert' => [

                'title' => '$GOOG up 1.43% on the day',

                'body' => '$GOOG gained 11.80 points to close at 835.67, up 1.43% on the day.',

            ],

            'badge' => 42,

            'sound' => 'default',

        ],

    ],

]);

$message = $message->withApnsConfig($config);

```

##### WebPush[¶](#webpush "Permalink to this headline")

You can find the full WebPush configuration reference in the official documentation:

[REST Resource: projects.messages.Webpush](https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages#webpushconfig)

```

use Kreait\Firebase\Messaging\WebPushConfig;

// Example from https://firebase.google.com/docs/cloud-messaging/admin/send-messages#webpush\_specific\_fields

$config = WebPushConfig::fromArray([

    'notification' => [

        'title' => '$GOOG up 1.43% on the day',

        'body' => '$GOOG gained 11.80 points to close at 835.67, up 1.43% on the day.',

        'icon' => 'https://my-server/icon.png',

    ],

    'fcm\_options' => [

        'link' => 'https://my-server/some-page',

    ],

]);

$message = $message->withWebPushConfig($config);

```

#### Adding platform independent FCM options[¶](#adding-platform-independent-fcm-options "Permalink to this headline")

You can find the full FCM Options configuration reference in the official documentation:

[REST Resource: projects.messages.fcm\_options](https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages#fcmoptions)

```

use Kreait\Firebase\Messaging\FcmOptions;

$fcmOptions = FcmOptions::create()

    ->withAnalyticsLabel('my-analytics-label');

// or

$fcmOptions = [

    'analytics\_label' => 'my-analytics-label';

];

$message = $message->withFcmOptions($fcmOptions);

```

#### Notification Sounds[¶](#notification-sounds "Permalink to this headline")

The SDK provides helper methods to add sounds to messages:

* `CloudMessage::withDefaultSounds()`

* `AndroidConfig::withDefaultSound()`

* `AndroidConfig::withSound($sound)`

* `ApnsConfig::withDefaultSound()`

* `ApnsConfig::withSound($sound)`

Note

WebPush notification don’t support the inclusion of sounds.

```

$message = CloudMessage::withTarget('token', $token)

    ->withNotification(['title' => 'Notification title', 'body' => 'Notification body'])

    ->withDefaultSounds() // Enables default notifications sounds on iOS and Android devices.

    ->withApnsConfig(

        ApnsConfig::new()

            ->withSound('bingbong.aiff')

            ->withBadge(1)

    )

;

```

#### Message Priority[¶](#message-priority "Permalink to this headline")

The SDK provides helper methods to define the priority of a message.

Note

You can learn more about message priorities for the different target platforms at

[Setting the priority of a message](https://firebase.google.com/docs/cloud-messaging/concept-options#setting-the-priority-of-a-message)

in the official Firebase documentation.

Note

Setting a message priority is optional. If you don’t set a priority, the Firebase backend or the target

platform uses their defined defaults.

##### Android[¶](#id3 "Permalink to this headline")

* `AndroidConfig::withNormalPriority()`

* `AndroidConfig::withHighPriority()`

* `AndroidConfig::withPriority(string $priority)`

##### iOS (APNS)[¶](#ios-apns "Permalink to this headline")

* `ApnsConfig::withPowerConservingPriority()`

* `ApnsConfig::withImmediatePriority()`

* `ApnsConfig::withPriority(string $priority)`

##### Web[¶](#id4 "Permalink to this headline")

* `WebPushConfig::withVeryLowUrgency()`

* `WebPushConfig::withLowUrgency()`

* `WebPushConfig::withNormalUrgency()`

* `WebPushConfig::withHighUrgency()`

* `WebPushConfig::withUrgency(string $urgency)`

##### Combined[¶](#combined "Permalink to this headline")

* `CloudMessage::withLowestPossiblePriority()`

* `CloudMessage::withHighestPossiblePriority()`

##### Example[¶](#example "Permalink to this headline")

```

$message = CloudMessage::withTarget('token', $token)

    ->withNotification([

        'title' => 'If you had an iOS device…',

        'body' => '… you would have received a very important message'

    ])

    ->withLowestPossiblePriority()

    ->withApnsConfig(

        ApnsConfig::new()

            ->withImmediatePriority()

            ->withNotification([

                'title => 'A very important message…',

 'body' => '… that requires your immediate attention.'

            ])

    )

;

```

#### Using Emojis[¶](#using-emojis "Permalink to this headline")

Firebase Messaging supports Emojis in Messages.

Note

You can find a full list of all currently available Emojis at

<https://www.unicode.org/emoji/charts/full-emoji-list.html>

```

// You can copy and paste an emoji directly into you source code

$text = "This is an emoji 😀";

$text = "This is an emoji \u{1F600}";

```

#### Sending a fully configured raw message[¶](#sending-a-fully-configured-raw-message "Permalink to this headline")

Note

The message will be parsed and validated by the SDK.

```

use Kreait\Firebase\Messaging\RawMessageFromArray;

$message = new RawMessageFromArray([

        'notification' => [

            // https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages#notification

            'title' => 'Notification title',

            'body' => 'Notification body',

            'image' => 'http://lorempixel.com/400/200/',

        ],

        'data' => [

            'key\_1' => 'Value 1',

            'key\_2' => 'Value 2',

        ],

        'android' => [

            // https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages#androidconfig

            'ttl' => '3600s',

            'priority' => 'normal',

            'notification' => [

                'title' => '$GOOG up 1.43% on the day',

                'body' => '$GOOG gained 11.80 points to close at 835.67, up 1.43% on the day.',

                'icon' => 'stock\_ticker\_update',

                'color' => '#f45342',

            ],

        ],

        'apns' => [

            // https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages#apnsconfig

            'headers' => [

                'apns-priority' => '10',

            ],

            'payload' => [

                'aps' => [

                    'alert' => [

                        'title' => '$GOOG up 1.43% on the day',

                        'body' => '$GOOG gained 11.80 points to close at 835.67, up 1.43% on the day.',

                    ],

                    'badge' => 42,

                ],

            ],

        ],

        'webpush' => [

            // https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages#webpushconfig

            'headers' => [

                'Urgency' => 'normal',

            ],

            'notification' => [

                'title' => '$GOOG up 1.43% on the day',

                'body' => '$GOOG gained 11.80 points to close at 835.67, up 1.43% on the day.',

                'icon' => 'https://my-server/icon.png',

            ],

        ],

        'fcm\_options' => [

            // https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages#fcmoptions

            'analytics\_label' => 'some-analytics-label'

        ]

    ]);

$messaging->send($message);

```

#### Validating messages[¶](#validating-messages "Permalink to this headline")

You can validate a message by sending a validation-only request to the Firebase REST API. If the message is invalid,

a KreaitFirebaseExceptionMessagingInvalidMessage exception is thrown, which you can catch to evaluate the raw

error message(s) that the API returned.

```

use Kreait\Firebase\Exception\Messaging\InvalidMessage;

try {

    $messaging->validate($message);

    // or

    $messaging->send($message, $validateOnly = true);

} catch (InvalidMessage $e) {

    print\_r($e->errors());

}

```

You can also use the `send\*` methods with an additional parameter:

```

$validateOnly = true;

$messaging->send($message, $validateOnly);

$messaging->sendMulticast($message, $tokens, $validateOnly);

$messaging->sendAll($messages, $validateOnly);

```

#### Validating Registration Tokens[¶](#validating-registration-tokens "Permalink to this headline")

If you have a set of registration tokens that you want to check for validity or if they are still registered

to your project, you can use the validateTokens() method:

```

$tokens = [...];

$result = $messaging->validateRegistrationTokens($tokens);

```

The result is an array with three keys containing the checked tokens:

* `valid` contains all tokens that are valid and registered to the current Firebase project

* `unknown` contains all tokens that are valid, but **not** registered to the current Firebase project

* `invalid` contains all invalid (=malformed) tokens

#### Topic management[¶](#topic-management "Permalink to this headline")

You can subscribe one or multiple devices to one or multiple messaging topics with the following methods:

```

$result = $messaging->subscribeToTopic($topic, $registrationTokenOrTokens);

$result = $messaging->subscribeToTopics($topics, $registrationTokenOrTokens);

$result = $messaging->unsubscribeFromTopic($topic, $registrationTokenOrTokens);

$result = $messaging->unsubscribeFromTopics($topics, $registrationTokenOrTokens);

$result = $messaging->unsubscribeFromAllTopics($registrationTokenOrTokens);

```

The result will return an array win which the keys are the topic names, and the values are the operation

results for the individual tokens.

Note

You can subscribe up to 1,000 devices in a single request. If you provide an array with over 1,000

registration tokens, the operation will fail with an error.

#### App instance management[¶](#app-instance-management "Permalink to this headline")

A registration token is related to an application that generated it. You can retrieve current information

about an app instance by passing a registration token to the `getAppInstance()` method.

```

$registrationToken = '...';

$appInstance = $messaging->getAppInstance($registrationToken);

// Return the full information as provided by the Firebase API

$instanceInfo = $appInstance->rawData();

/\* Example output for an Android application instance:

 [

 "applicationVersion" => "1060100"

 "connectDate" => "2019-07-21"

 "attestStatus" => "UNKNOWN"

 "application" => "com.vendor.application"

 "scope" => "\*"

 "authorizedEntity" => "..."

 "rel" => array:1 [

 "topics" => array:3 [

 "test-topic" => array:1 [

 "addDate" => "2019-07-21"

 ]

 "test-topic-5d35b46a15094" => array:1 [

 "addDate" => "2019-07-22"

 ]

 "test-topic-5d35b46b66c31" => array:1 [

 "addDate" => "2019-07-22"

 ]

 ]

 ]

 "connectionType" => "WIFI"

 "appSigner" => "..."

 "platform" => "ANDROID"

 ]

\*/

/\* Example output for a web application instance

 [

 "application" => "webpush"

 "scope" => ""

 "authorizedEntity" => "..."

 "rel" => array:1 [

 "topics" => array:2 [

 "test-topic-5d35b445b830a" => array:1 [

 "addDate" => "2019-07-22"

 ]

 "test-topic-5d35b446c0839" => array:1 [

 "addDate" => "2019-07-22"

 ]

 ]

 ]

 "platform" => "BROWSER"

 ]

\*/

```

Note

As the data returned by the Google Instance ID API can return differently formed results depending on the

application or platform, it is currently difficult to add reliable convenience methods for specific

fields in the raw data.

##### Working with topic subscriptions[¶](#working-with-topic-subscriptions "Permalink to this headline")

You can retrieve all topic subscriptions for an app instance with the `topicSubscriptions()` method:

```

$appInstance = $messaging->getAppInstance('<registration token>');

/\*\* @var \Kreait\Firebase\Messaging\TopicSubscriptions $subscriptions \*/

$subscriptions = $appInstance->topicSubscriptions();

foreach ($subscriptions as $subscription) {

    echo "{$subscription->registrationToken()} is subscribed to {$subscription->topic()}\n";

}

```

### Cloud Firestore[¶](#cloud-firestore "Permalink to this headline")

This SDK provides a bridge to the [google/cloud-firestore](https://packagist.org/packages/google/cloud-firestore)

package. You can enable the component in the SDK by adding the package to your project dependencies:

```

composer require google/cloud-firestore

```

Note

The `google/cloud-firestore` package requires the gRPC PHP extension to be installed. You can find installation

instructions for gRPC at [github.com/grpc/grpc](https://github.com/grpc/grpc/tree/master/src/php). The following

projects aim to provide support for Firestore without the need to install the gRPC PHP extension, but have to

be set up separately:

* [ahsankhatri/firestore-php](https://github.com/ahsankhatri/firestore-php)

* [morrislaptop/firestore-php](https://github.com/morrislaptop/firestore-php)

Before you start, please read about Firestore in the official documentation:

* [Official Documentation](https://firebase.google.com/docs/firestore/)

* [google/cloud-firestore on GitHub](https://github.com/googleapis/google-cloud-php-firestore)

* [PHP API Documentation](https://googleapis.github.io/google-cloud-php/#/docs/cloud-firestore)

* [PHP Usage Examples](https://github.com/GoogleCloudPlatform/php-docs-samples/tree/master/firestore)

#### Initializing the Firestore component[¶](#initializing-the-firestore-component "Permalink to this headline")

**With the SDK**

```

$firestore = $factory->createFirestore();

```

**With Dependency Injection** ([Symfony Bundle](https://github.com/kreait/firebase-bundle)/[Laravel/Lumen Package](https://github.com/kreait/laravel-firebase))

```

use Kreait\Firebase\Contract\Firestore;

class MyService

{

    public function \_\_construct(Firestore $firestore)

    {

        $this->firestore = $firestore;

    }

}

```

**With the Laravel** `app()` **helper** ([Laravel/Lumen Package](https://github.com/kreait/laravel-firebase))

```

$firestore = app('firebase.firestore');

```

#### Getting started[¶](#getting-started "Permalink to this headline")

```

$database = $firestore->database();

```

`$database` is an instance of `Google\Cloud\Firestore\FirestoreClient`. Please refer to the links above for

guidance on how to proceed from here.

### Cloud Storage[¶](#cloud-storage "Permalink to this headline")

Cloud Storage for Firebase stores your data in [Google Cloud Storage](https://cloud.google.com/storage),

an exabyte scale object storage solution with high availability and global redundancy.

This SDK provides a bridge to the [google/cloud-storage](https://packagist.org/packages/google/cloud-storage)

package. You can enable the component in the SDK by adding the package to your project dependencies:

Before you start, please read about Firebase Cloud Storage in the official documentation:

* [Firebase Cloud Storage](https://firebase.google.com/docs/storage/)

* [Introduction to the Admin Cloud Storage API](https://firebase.google.com/docs/storage/admin/start)

* [PHP API Documentation](https://googleapis.github.io/google-cloud-php/#/docs/cloud-storage)

* [PHP Usage examples](https://github.com/GoogleCloudPlatform/php-docs-samples/blob/master/storage)

#### Initializing the Storage component[¶](#initializing-the-storage-component "Permalink to this headline")

**With the SDK**

```

$storage = $factory->createStorage();

```

**With Dependency Injection** ([Symfony Bundle](https://github.com/kreait/firebase-bundle)/[Laravel/Lumen Package](https://github.com/kreait/laravel-firebase))

```

use Kreait\Firebase\Contract\Storage;

class MyService

{

    public function \_\_construct(Storage $storage)

    {

        $this->storage = $storage;

    }

}

```

**With the Laravel** `app()` **helper** ([Laravel/Lumen Package](https://github.com/kreait/laravel-firebase))

```

$storage = app('firebase.storage');

```

#### Getting started[¶](#getting-started "Permalink to this headline")

```

$storageClient = $storage->getStorageClient();

$defaultBucket = $storage->getBucket();

$anotherBucket = $storage->getBucket('another-bucket');

```

#### Default Storage bucket[¶](#default-storage-bucket "Permalink to this headline")

Note

It is not necessary to change the default storage bucket in most cases.

The SDK assumes that your project’s default storage bucket name has the format `<project-id>.appspot.com`

and will configure the storage instance accordingly.

If you want to change the default bucket your instance works with, you can specify the name when using

the factory:

```

use Kreait\Firebase\Factory;

$storage = (new Factory())

    ->withDefaultStorageBucket('another-default-bucket')

    ->createStorage();

```

### Realtime Database[¶](#realtime-database "Permalink to this headline")

Note

The Realtime Database API currently does not support realtime event listeners.

#### Initializing the Realtime Database component[¶](#initializing-the-realtime-database-component "Permalink to this headline")

**With the SDK**

```

$database = $factory->createDatabase();

```

**With Dependency Injection** ([Symfony Bundle](https://github.com/kreait/firebase-bundle)/[Laravel/Lumen Package](https://github.com/kreait/laravel-firebase))

```

use Kreait\Firebase\Contract\Database;

class MyService

{

    public function \_\_construct(Database $database)

    {

        $this->database = $database;

    }

}

```

**With the Laravel** `app()` **helper** ([Laravel/Lumen Package](https://github.com/kreait/laravel-firebase))

```

$database = app('firebase.database');

```

#### Retrieving data[¶](#retrieving-data "Permalink to this headline")

Every node in your database can be accessed through a Reference:

```

$reference = $database->getReference('path/to/child/location');

```

Note

Creating a reference does not result in a request to your Database. Requests to your Firebase

applications are executed with the `getSnapshot()` and `getValue()` methods only.

You can then retrieve a Database Snapshot for the Reference or its value directly:

```

$snapshot = $reference->getSnapshot();

$value = $snapshot->getValue();

// or

$value = $reference->getValue();

```

##### Database Snapshots[¶](#database-snapshots "Permalink to this headline")

Database Snapshots are immutable copies of the data at a Firebase Database location at the time of a

query. The can’t be modified and will never change.

```

$snapshot = $reference->getSnapshot();

$value = $snapshot->getValue();

$value = $reference->getValue(); // Shortcut for $reference->getSnapshot()->getValue();

```

Snapshots provide additional methods to work with and analyze the contained value:

* `exists()` returns true if the Snapshot contains any (non-null) data.

* `getChild()` returns another Snapshot for the location at the specified relative path.

* `getKey()` returns the key (last part of the path) of the location of the Snapshot.

* `getReference()` returns the Reference for the location that generated this Snapshot.

* `getValue()` returns the data contained in this Snapshot.

* `hasChild()` returns true if the specified child path has (non-null) data.

* `hasChildren()` returns true if the Snapshot has any child properties, i.e. if the value is an array.

* `numChildren()` returns the number of child properties of this Snapshot, if there are any.

##### Queries[¶](#queries "Permalink to this headline")

You can use Queries to filter and order the results returned from the Realtime Database. Queries behave exactly

like References. That means you can execute any method on a Query that you can execute on a Reference.

Note

You can combine every filter query with every order query, but not multiple queries of each type.

Shallow queries are a special case: they can not be combined with any other query method.

##### Shallow queries[¶](#shallow-queries "Permalink to this headline")

This is an advanced feature, designed to help you work with large datasets without needing to download

everything. Set this to true to limit the depth of the data returned at a location. If the data at

the location is a JSON primitive (string, number or boolean), its value will simply be returned.

If the data snapshot at the location is a JSON object, the values for each key will be

truncated to true.

Detailed information can be found on

[the official Firebase documentation page for shallow queries](https://firebase.google.com/docs/database/rest/retrieve-data#shallow)

```

$database->getReference('currencies')

    // order the reference's children by their key in ascending order

    ->shallow()

    ->getSnapshot();

```

A convenience method is available to retrieve the key names of a reference’s children:

```

$database->getReference('currencies')->getChildKeys(); // returns an array of key names

```

##### Ordering data[¶](#ordering-data "Permalink to this headline")

The official Firebase documentation explains

[How data is ordered](https://firebase.google.com/docs/database/rest/retrieve-data#section-rest-ordered-data).

Data is always ordered in ascending order.

You can only order by one property at a time - if you try to order by multiple properties,

e.g. by child and by value, an exception will be thrown.

###### By key[¶](#by-key "Permalink to this headline")

```

$database->getReference('currencies')

    // order the reference's children by their key in ascending order

    ->orderByKey()

    ->getSnapshot();

```

###### By value[¶](#by-value "Permalink to this headline")

Note

In order to order by value, you must define an index, otherwise the Firebase API will

refuse the query.

```

{

 "currencies": {

 ".indexOn": ".value"

 }

}

```

```

$database->getReference('currencies')

    // order the reference's children by their value in ascending order

    ->orderByValue()

    ->getSnapshot();

```

###### By child[¶](#by-child "Permalink to this headline")

Note

In order to order by a child value, you must define an index, otherwise the Firebase API will

refuse the query.

```

{

 "people": {

 ".indexOn": "height"

 }

}

```

```

$database->getReference('people')

    // order the reference's children by the values in the field 'height' in ascending order

    ->orderByChild('height')

    ->getSnapshot();

```

##### Filtering data[¶](#filtering-data "Permalink to this headline")

To be able to filter results, you must also define an order.

###### limitToFirst[¶](#limittofirst "Permalink to this headline")

```

$database->getReference('people')

    // order the reference's children by the values in the field 'height'

    ->orderByChild('height')

    // limits the result to the first 10 children (in this case: the 10 shortest persons)

    // values for 'height')

    ->limitToFirst(10)

    ->getSnapshot();

```

###### limitToLast[¶](#limittolast "Permalink to this headline")

```

$database->getReference('people')

    // order the reference's children by the values in the field 'height'

    ->orderByChild('height')

    // limits the result to the last 10 children (in this case: the 10 tallest persons)

    ->limitToLast(10)

    ->getSnapshot();

```

###### startAt[¶](#startat "Permalink to this headline")

```

$database->getReference('people')

    // order the reference's children by the values in the field 'height'

    ->orderByChild('height')

    // returns all persons taller than or exactly 1.68 (meters)

    ->startAt(1.68)

    ->getSnapshot();

```

###### startAfter[¶](#startafter "Permalink to this headline")

Note

The `startAfter` query filter has been added to the Firebase JS SDK on 2021-02-11. This PHP SDK

implements this in the same way as the other filters, but `startAfter` does not seem to have

an effect when used with the Firebase REST API. If you happen to know why or you tried it

and it does indeed work, please let me know via the SDK’s git repo.

```

$database->getReference('people')

    // order the reference's children by the values in the field 'height'

    ->orderByChild('height')

    // returns all persons taller than 1.68 (meters)

    ->startAfter(1.68)

    ->getSnapshot();

```

###### endAt[¶](#endat "Permalink to this headline")

```

$database->getReference('people')

    // order the reference's children by the values in the field 'height'

    ->orderByChild('height')

    // returns all persons shorter than or exactly 1.98 (meters)

    ->endAt(1.98)

    ->getSnapshot();

```

###### endBefore[¶](#endbefore "Permalink to this headline")

Note

The `endBefore` query filter has been added to the Firebase JS SDK on 2021-02-11. This PHP SDK

implements this in the same way as the other filters, but `endBefore` does not seem to have

an effect when used with the Firebase REST API. If you happen to know why or you tried it

and it does indeed work, please let me know via the SDK’s git repo.

```

$database->getReference('people')

    // order the reference's children by the values in the field 'height'

    ->orderByChild('height')

    // returns all persons shorter than 1.98 (meters)

    ->endBefore(1.98)

    ->getSnapshot();

```

###### equalTo[¶](#equalto "Permalink to this headline")

```

$database->getReference('people')

    // order the reference's children by the values in the field 'height'

    ->orderByChild('height')

    // returns all persons being exactly 1.98 (meters) tall

    ->equalTo(1.98)

    ->getSnapshot();

```

#### Saving data[¶](#saving-data "Permalink to this headline")

##### Set/replace values[¶](#set-replace-values "Permalink to this headline")

For basic write operations, you can use set() to save data to a specified reference,

replacing any existing data at that path. For example a configuration array for

a website might be set as follows:

```

$database->getReference('config/website')

   ->set([

       'name' => 'My Application',

       'emails' => [

           'support' => 'support@domain.tld',

           'sales' => 'sales@domain.tld',

       ],

       'website' => 'https://app.domain.tld',

      ]);

$database->getReference('config/website/name')->set('New name');

```

Note

Using `set()` overwrites data at the specified location, including any child nodes.

##### Update specific fields[¶](#update-specific-fields "Permalink to this headline")

To simultaneously write to specific children of a node without overwriting other child nodes,

use the update() method.

When calling `update()`, you can update lower-level child values by specifying a path for

the key. If data is stored in multiple locations to scale better, you can update all

instances of that data using data fan-out.

For example, in a blogging app you might want to add a post and simultaneously update it

to the recent activity feed and the posting user’s activity feed using code like this:

```

$uid = 'some-user-id';

$postData = [

    'title' => 'My awesome post title',

    'body' => 'This text should be longer',

];

// Create a key for a new post

$newPostKey = $database->getReference('posts')->push()->getKey();

$updates = [

    'posts/'.$newPostKey => $postData,

    'user-posts/'.$uid.'/'.$newPostKey => $postData,

];

$database->getReference() // this is the root reference

   ->update($updates);

```

##### Writing lists[¶](#writing-lists "Permalink to this headline")

Use the `push()` method to append data to a list in multiuser applications. The `push()` method

generates a unique key every time a new child is added to the specified Firebase reference.

By using these auto-generated keys for each new element in the list, several clients can

add children to the same location at the same time without write conflicts.

The unique key generated by `push()` is based on a timestamp, so list

items are automatically ordered chronologically.

You can use the reference to the new data returned by the `push()` method to get the value of the

child’s auto-generated key or set data for the child. The `getKey()` method of a

`push()` reference contains the auto-generated key.

```

$postData = [...];

$postRef = $database->getReference('posts')->push($postData);

$postKey = $postRef->getKey(); // The key looks like this: -KVquJHezVLf-lSye6Qg

```

##### Server values[¶](#server-values "Permalink to this headline")

Server values can be written at a location using a placeholder value which is an object with a single

`.sv` key. The value for that key is the type of server value you wish to set.

Firebase currently supports only one server value: `timestamp`. You can either set it

manually in your write operation, or use a constant from the `Firebase\Database` class.

The following to usages are equivalent:

```

$ref = $database->getReference('posts/my-post')

          ->set('created\_at', ['.sv' => 'timestamp']);

$ref = $database->getReference('posts/my-post')

          ->set('created\_at', Database::SERVER\_TIMESTAMP);

```

##### Delete data[¶](#delete-data "Permalink to this headline")

You can delete a reference, including all data it contains, with the `remove()` method:

```

$database->getReference('posts')->remove();

```

You can also delete by specifying null as the value for another write operation such as

`set()` or `update()`.

```

$database->getReference('posts')->set(null);

```

You can also delete in bulk using the function `removeChildren()`:

```

$data->getReference()->removeChildren([

    'posts/post1',

    'user-posts/f55dee9a-dd67-4e78-bd7d-f1b4be157a53/post1',

    'users/f55dee9a-dd67-4e78-bd7d-f1b4be157a53'

]);

```

#### Database transactions[¶](#database-transactions "Permalink to this headline")

You can use transaction to update data according to its existing state. For example, if you want to increase

an upvote counter, and want to make sure the count accurately reflects multiple, simultaneous upvotes,

use a transaction to write the new value to the counter. Instead of two writes that change the

counter to the same number, one of the write requests fails and you can then retry the

request with the new value.

##### Replace data inside a transaction[¶](#replace-data-inside-a-transaction "Permalink to this headline")

```

use Kreait\Firebase\Database\Transaction;

$counterRef = $database->getReference('counter');

$result = $database->runTransaction(function (Transaction $transaction) use ($counterRef) {

    // You have to snapshot the reference in order to change its value

    $counterSnapshot = $transaction->snapshot($counterRef);

    // Get the existing value from the snapshot

    $counter = $counterSnapshot->getValue() ?: 0;

    $newCounter = ++$counter;

    // If the value hasn't changed in the Realtime Database while we are

    // incrementing it, the transaction will be a success.

    $transaction->set($counterRef, $newCounter);

    return $newCounter;

});

```

##### Delete data inside a transaction[¶](#delete-data-inside-a-transaction "Permalink to this headline")

Likewise, you can wrap the removal of a reference in a transaction as well: you can remove the reference

only if it hasn’t changed in the meantime.

```

use Kreait\Firebase\Database\Transaction;

$toBeDeleted = $database->getReference('to-be-deleted');

$database->runTransaction(function (Transaction $transaction) use ($toBeDeleted) {

    $transaction->snapshot($toBeDeleted);

    $transaction->remove($toBeDeleted);

});

```

##### Handling transaction failures[¶](#handling-transaction-failures "Permalink to this headline")

If you haven’t snapshotted a reference before trying to change it, the operation will fail

with a `\Kreait\Firebase\Exception\Database\ReferenceHasNotBeenSnapshotted` error.

If the reference has changed in the Realtime Database after you started the transaction,

the transaction will fail with a `\Kreait\Firebase\Exception\Database\TransactionFailed`

error.

```

use Kreait\Firebase\Database\Transaction;

use Kreait\Firebase\Exception\Database\ReferenceHasNotBeenSnapshotted;

use Kreait\Firebase\Exception\Database\TransactionFailed;

$ref = $database->getReference('my-ref');

try {

    $database->runTransaction(function (Transaction $transaction) use ($ref) {

        // $transaction->snapshot($ref);

        $ref->set('value change without a transaction');

        $transaction->set($ref, 'this will fail');

    });

} catch (ReferenceHasNotBeenSnapshotted $e) {

    $referenceInQuestion = $e->getReference();

    echo $e->getReference()->getUri().': '.$e->getMessage();

} catch (TransactionFailed $e) {

    $referenceInQuestion = $e->getReference();

    $failedRequest = $e->getRequest();

    $failureResponse = $e->getResponse();

    echo $e->getReference()->getUri().': '.$e->getMessage();

}

```

#### Debugging API exceptions[¶](#debugging-api-exceptions "Permalink to this headline")

When a request to Firebase fails, the SDK will throw a `\Kreait\Firebase\Exception\ApiException` that

includes the sent request and the received response object:

```

try {

    $database->getReference('forbidden')->getValue();

} catch (ApiException $e) {

    /\*\* @var \Psr\Http\Message\RequestInterface $request \*/

    $request = $e->getRequest();

    /\*\* @var \Psr\Http\Message\ResponseInterface|null $response \*/

    $response = $e->getResponse();

    echo $request->getUri().PHP\_EOL;

    echo $request->getBody().PHP\_EOL;

    if ($response) {

        echo $response->getBody();

    }

}

```

#### Database rules[¶](#database-rules "Permalink to this headline")

Learn more about the usage of Firebase Realtime Database Rules in the

[official documentation](https://firebase.google.com/docs/database/security/).

```

use Kreait\Firebase\Database\RuleSet;

// The default rules allow full read and write access to authenticated users of your app

$ruleSet = RuleSet::default();

// This level of access means anyone can read or write to your database. You should

// configure more secure rules before launching your app.

$ruleSet = RuleSet::public();

// Private rules disable read and write access to your database by users.

// With these rules, you can only access the database through the

// Firebase console and the Admin SDKs.

$ruleSet = RuleSet::private();

// You can define custom rules

$ruleSet = RuleSet::fromArray(['rules' => [

    '.read' => true,

    '.write' => false,

    'users' => [

        '$uid' => [

            '.read' => '$uid === auth.uid',

            '.write' => '$uid === auth.uid',

        ]

    ]

]]);

$database->updateRules($ruleSet);

$freshRuleSet = $database->getRuleSet(); // Returns a new RuleSet instance

$actualRules = $ruleSet->getRules(); // returns an array

```

#### Authenticate with limited privileges[¶](#authenticate-with-limited-privileges "Permalink to this headline")

As a best practice, a service should have access to only the resources it needs. To get more fine-grained control

over the resources a Firebase app instance can access, use a unique identifier in your Security Rules to represent

your service. Then set up appropriate rules which grant your service access to the resources it needs. For example:

```

{

 "rules": {

 "public\_resource": {

 ".read": true,

 ".write": true

 },

 "some\_resource": {

 ".read": "auth.uid === 'my-service-worker'",

 ".write": false

 },

 "another\_resource": {

 ".read": "auth.uid === 'my-service-worker'",

 ".write": "auth.uid === 'my-service-worker'"

 }

 }

}

```

Then, when instantiating the database component of the SDK, use the `withDatabaseAuthVariableOverride()` method

to override the auth object used by your database rules. In this custom auth object, set the `uid` field to the

identifier you used to represent your service in your Security Rules.

```

use Kreait\Firebase\Factory;

$factory = (new Factory)

    ->withServiceAccount('/path/to/firebase\_credentials.json')

    ->withDatabaseUri('https://my-project-default-rtdb.firebaseio.com');

$database = $factory

    ->withDatabaseAuthVariableOverride('my-service-worker')

    ->createDatabase();

// $database now only has access as defined in the Security Rules

```

In some cases, you may want to downscope the Admin SDKs to act as an unauthenticated client. You can do this by

providing a value of `null` for the database auth variable override.

```

$database = $factory

    ->withDatabaseAuthVariableOverride(null)

    ->createDatabase();

// $database now only has access to public resources

```

### Authentication[¶](#authentication "Permalink to this headline")

Before you start, please read about Firebase Authentication in the official documentation:

* [Introduction to the Admin Database API](https://firebase.google.com/docs/database/admin/start)

* [Create custom tokens](https://firebase.google.com/docs/auth/admin/create-custom-tokens)

* [Verify ID Tokens](https://firebase.google.com/docs/auth/admin/verify-id-tokens)

* [Manage Session Cookies](https://firebase.google.com/docs/auth/admin/manage-cookies)

* [Revoke refresh tokens](https://firebase.google.com/docs/reference/admin/node/admin.auth.Auth#revokeRefreshTokens)

Before you can access the Firebase Realtime Database from a server using the Firebase Admin SDK,

you must authenticate your server with Firebase. When you authenticate a server, rather than

sign in with a user account’s credentials as you would in a client app, you authenticate

with a [service account](https://developers.google.com/identity/protocols/OAuth2ServiceAccount)

which identifies your server to Firebase.

You can get two different levels of access when you authenticate using the Firebase Admin SDK:

**Administrative privileges**: Complete read and write access to a project’s Realtime Database.

Use with caution to complete administrative tasks such as data migration or restructuring

that require unrestricted access to your project’s resources.

**Limited privileges**: Access to a project’s Realtime Database, limited to only the resources

your server needs. Use this level to complete administrative tasks that have well-defined

access requirements. For example, when running a summarization job that reads data

across the entire database, you can protect against accidental writes by setting

a read-only security rule and then initializing the Admin SDK with privileges

limited by that rule.

#### Initializing the Auth component[¶](#initializing-the-auth-component "Permalink to this headline")

**With the SDK**

```

$auth = $factory->createAuth();

```

**With Dependency Injection** ([Symfony Bundle](https://github.com/kreait/firebase-bundle)/[Laravel/Lumen Package](https://github.com/kreait/laravel-firebase))

```

use Kreait\Firebase\Contract\Auth;

class MyService

{

    public function \_\_construct(Auth $auth)

    {

        $this->auth = $auth;

    }

}

```

**With the Laravel** `app()` **helper** ([Laravel/Lumen Package](https://github.com/kreait/laravel-firebase))

```

$auth = app('firebase.auth');

```

#### Create custom tokens[¶](#id2 "Permalink to this headline")

The Firebase Admin SDK has a built-in method for creating custom tokens. At a minimum, you need to provide a uid,

which can be any string but should uniquely identify the user or device you are authenticating.

These tokens expire after one hour.

```

$uid = 'some-uid';

$customToken = $auth->createCustomToken($uid);

```

You can also optionally specify additional claims to be included in the custom token. For example,

below, a premiumAccount field has been added to the custom token, which will be available in

the auth / request.auth objects in your Security Rules:

```

$uid = 'some-uid';

$additionalClaims = [

    'premiumAccount' => true

];

$customToken = $auth->createCustomToken($uid, $additionalClaims);

$customTokenString = $customToken->toString();

```

Note

This library uses [lcobucci/jwt](https://github.com/lcobucci/jwt) to work with JSON Web Tokens (JWT).

You can find the usage instructions at <https://lcobucci-jwt.readthedocs.io/>.

#### Verify a Firebase ID Token[¶](#verify-a-firebase-id-token "Permalink to this headline")

If a Firebase client app communicates with your server, you might need to identify the currently signed-in user.

To do so, verify the integrity and authenticity of the ID token and retrieve the uid from it.

You can use the uid transmitted in this way to securely identify the currently signed-in user on your server.

Note

Many use cases for verifying ID tokens on the server can be accomplished by using Security Rules for the

[Firebase Realtime Database](https://firebase.google.com/docs/database/security/) and

[Cloud Storage](https://firebase.google.com/docs/storage/security/).

See if those solve your problem before verifying ID tokens yourself.

Warning

The ID token verification methods included in the Firebase Admin SDKs are meant to verify ID tokens that come

from the client SDKs, not the custom tokens that you create with the Admin SDKs.

See [Auth tokens](https://firebase.google.com/docs/auth/users/#auth_tokens)

for more information.

Use `Auth::verifyIdToken()` to verify an ID token:

```

use Kreait\Firebase\Exception\Auth\FailedToVerifyToken;

$idTokenString = '...';

try {

    $verifiedIdToken = $auth->verifyIdToken($idTokenString);

} catch (FailedToVerifyToken $e) {

    echo 'The token is invalid: '.$e->getMessage();

}

$uid = $verifiedIdToken->claims()->get('sub');

$user = $auth->getUser($uid);

```

`Auth::verifyIdToken()` accepts the following parameters:

| Parameter | Type | Description |

| --- | --- | --- |

| `idToken` | string|Token | **(required)** The ID token to verify |

| `checkIfRevoked` | boolean | (optional, default: `false` ) check if the ID token is revoked |

| `leewayInSeconds` | positive-int|null | (optional, default: `null`) number of seconds to allow a token to be expired, in case that there is a clock skew between the signing and the verifying server. |

Note

This library uses [lcobucci/jwt](https://github.com/lcobucci/jwt) to work with JSON Web Tokens (JWT).

You can find the usage instructions at <https://lcobucci-jwt.readthedocs.io/>.

#### Custom Authentication Flows[¶](#custom-authentication-flows "Permalink to this headline")

Warning

It is recommended that you use the Firebase Client SDKs to perform user authentication. Once

signed in via a client SDK, you should pass the logged-in user’s current ID token to your

PHP endpoint and [verify the ID token](#verify-a-firebase-id-token) with each request

to your backend.

Each of the methods documented below will return an instance of `Kreait\Firebase\Auth\SignInResult\SignInResult`

with the following accessors:

```

$signInResult->idToken(); // string|null

$signInResult->firebaseUserId(); // string|null

$signInResult->accessToken(); // string|null

$signInResult->refreshToken(); // string|null

$signInResult->data(); // array

$signInResult->asTokenResponse(); // array

```

`SignInResult::data()` returns the full payload of the response returned by the Firebase API,

`SignInResult::asTokenResponse()` returns the Sign-In result in a format that can be returned to

clients:

```

$tokenResponse = [

    'token\_type' => 'Bearer',

    'access\_token' => '...',

    'id\_token' => '...',

    'refresh\_token' => '...',

    'expires\_in' => 3600,

];

```

Note

Not all sign-in methods return all types of tokens.

##### Anonymous Sign In[¶](#anonymous-sign-in "Permalink to this headline")

Note

This method will create a new user in the Firebase Auth User Database each time

it is invoked

```

$signInResult = $auth->signInAnonymously();

```

##### Sign In with Email and Password[¶](#sign-in-with-email-and-password "Permalink to this headline")

```

$signInResult = $auth->signInWithEmailAndPassword($email, $clearTextPassword);

```

##### Sign In with Email and Oob Code[¶](#sign-in-with-email-and-oob-code "Permalink to this headline")

```

$signInResult = $auth->signInWithEmailAndOobCode($email, $oobCode);

```

##### Sign In with a Custom Token[¶](#sign-in-with-a-custom-token "Permalink to this headline")

```

$signInResult = $auth->signInWithCustomToken($customToken);

```

##### Sign In with a Refresh Token[¶](#sign-in-with-a-refresh-token "Permalink to this headline")

```

$signInResult = $auth->signInWithRefreshToken($refreshToken);

```

##### Sign In with IdP credentials[¶](#sign-in-with-idp-credentials "Permalink to this headline")

IdP (Identity Provider) credentials are credentials provided by authentication providers other than Firebase,

for example Facebook, Github, Google or Twitter. You can find the currently supported authentication providers

in the

[official Firebase documentation](https://firebase.google.com/docs/projects/provisioning/configure-oauth#add-idp).

This could be useful if you already have “Sign in with X” implemented in your application, and want to

authenticate the same user with Firebase.

Once you have received those credentials, you can use them to sign a user in with them:

```

$signInResult = $auth->signInWithIdpAccessToken($provider, string $accessToken, $redirectUrl = null, ?string $oauthTokenSecret = null, ?string $linkingIdToken = null, ?string $rawNonce = null);

$signInResult = $auth->signInWithIdpIdToken($provider, $idToken, $redirectUrl = null, ?string $linkingIdToken = null, ?string $rawNonce = null);

```

##### Sign In without a token[¶](#sign-in-without-a-token "Permalink to this headline")

```

$signInResult = $auth->signInAsUser($userOrUid, array $claims = null);

```

##### Linking and Unlinking Identity Providers[¶](#linking-and-unlinking-identity-providers "Permalink to this headline")

For linking IdP you can add use any of above methods for signing in with IdP credentials, by providing the ID token of

a user to link to as an additional parameter:

```

$signInResult = $auth->signInWithIdpAccessToken($provider, $accessToken, $redirectUrl = null, $oauthTokenSecret = null, $linkingIdToken);

$signInResult = $auth->signInWithGoogleIdToken($idToken, $redirectUrl = null, $linkingIdToken);

```

You can unlink a provider from a given user with the `unlinkProvider()` method:

```

$auth->unlinkProvider($uid, $provider)

```

#### Invalidate user sessions[¶](#invalidate-user-sessions "Permalink to this headline")

This will revoke all sessions for a specified user and disable any new ID tokens for existing sessions from getting

minted. **Existing ID tokens may remain active until their natural expiration (one hour).** To verify that

ID tokens are revoked, use `Auth::verifyIdToken()` with the second parameter set to `true`.

If the check fails, a `RevokedIdToken` exception will be thrown.

```

use Kreait\Firebase\Exception\Auth\RevokedIdToken;

$auth->revokeRefreshTokens($uid);

try {

    $verifiedIdToken = $auth->verifyIdToken($idTokenString, $checkIfRevoked = true);

} catch (RevokedIdToken $e) {

    echo $e->getMessage();

}

```

Note

Because Firebase ID tokens are stateless JWTs, you can determine a token has been revoked only by requesting the

token’s status from the Firebase Authentication backend. For this reason, performing this check on your server

is an expensive operation, requiring an extra network round trip. You can avoid making this network request

by setting up Firebase Rules that check for revocation rather than using the Admin SDK to make the check.

For more information, please visit

[Google: Detect ID token revocation in Database Rules](https://firebase.google.com/docs/auth/admin/manage-sessions#detect_id_token_revocation_in_database_rules)

#### Session Cookies[¶](#session-cookies "Permalink to this headline")

Firebase Auth provides server-side session cookie management for traditional websites that rely on session cookies.

This solution has several advantages over client-side short-lived ID tokens, which may require a redirect mechanism

each time to update the session cookie on expiration:

* Improved security via JWT-based session tokens that can only be generated using authorized service accounts.

* Stateless session cookies that come with all the benefit of using JWTs for authentication. The session cookie has

the same claims (including custom claims) as the ID token, making the same permissions checks enforceable on the

session cookies.

* Ability to create session cookies with custom expiration times ranging from 5 minutes to 2 weeks.

* Flexibility to enforce cookie policies based on application requirements: domain, path, secure, httpOnly, etc.

* Ability to revoke session cookies when token theft is suspected using the existing refresh token revocation API.

* Ability to detect session revocation on major account changes.

You can learn more about Firebase Session Cookies in the official documentation:

* [Manage Session Cookies](https://firebase.google.com/docs/auth/admin/manage-cookies)

Warning

Creating and verifying session cookies when using tenants is currently not possible. Please follow

[this issue on GitHub](https://github.com/firebase/firebase-admin-python/issues/577) or

[in the Google Issue Tracker](https://issuetracker.google.com/issues/204377229) for updates.

##### Create session cookie[¶](#create-session-cookie "Permalink to this headline")

Given an ID token sent to your server application from a client application, you can convert it to a session cookie:

```

use Kreait\Firebase\Auth\CreateSessionCookie\FailedToCreateSessionCookie;

$idToken = '...';

// The TTL must be between 5 minutes and 2 weeks and can be provided as

// an integer value in seconds or a DateInterval

$fiveMinutes = 300;

$oneWeek = new \DateInterval('P7D');

try {

    $sessionCookieString = $auth->createSessionCookie($idToken, $oneWeek);

} catch (FailedToCreateSessionCookie $e) {

    echo $e->getMessage();

}

```

##### Verify a Firebase Session Cookie[¶](#verify-a-firebase-session-cookie "Permalink to this headline")

Use `Auth::verifySessionCookie()` to verify a Session Cookie:

```

use Kreait\Firebase\Exception\Auth\FailedToVerifySessionCookie;

$sessionCookieString = '...';

try {

    $verifiedSessionCookie = $auth->verifySessionCookie($sessionCookieString);

} catch (FailedToVerifySessionCookie $e) {

    echo 'The Session Cookie is invalid: '.$e->getMessage();

}

$uid = $verifiedSessionCookie->claims()->get('sub');

$user = $auth->getUser($uid);

```

`Auth::verifySessionCookie()` accepts the following parameters:

| Parameter | Type | Description |

| --- | --- | --- |

| `sessionCookie` | string | **(required)** The Session Cookie to verify |

| `checkIfRevoked` | boolean | (optional, default: `false` ) check if the ID token is revoked |

| `leewayInSeconds` | positive-int|null | (optional, default: `null`) number of seconds to allow a Session Cookie to be expired, in case that there is a clock skew between the signing and the verifying server. |

Note

This library uses [lcobucci/jwt](https://github.com/lcobucci/jwt) to work with JSON Web Tokens (JWT).

You can find the usage instructions at <https://lcobucci-jwt.readthedocs.io/>.

#### Tenant Awareness[¶](#tenant-awareness "Permalink to this headline")

Note

Multi-tenancy support requires Google Cloud’s Identity Platform (GCIP). To learn more about GCIP,

including pricing and features, see the [GCIP documentation](https://cloud.google.com/identity-platform?hl=zh-Cn).

Before multi-tenancy can be used on a Google Cloud Identity Platform project, tenants must be allowed on that

project via the Cloud Console UI.

In order to manage users, create custom tokens, verify ID tokens and sign in users in the scope of a tenant, you

can configure the factory with a tenant ID:

```

$tenantUnawareAuth = $factory->createAuth();

$tenantAwareAuth = $factory

    ->withTenantId('my-tenant-id')

    ->createAuth();

```

### User management[¶](#user-management "Permalink to this headline")

The Firebase Admin SDK for PHP provides an API for managing your Firebase users with elevated privileges.

The admin user management API gives you the ability to programmatically retrieve, create, update, and

delete users without requiring a user’s existing credentials and without worrying about client-side

rate limiting.

#### User Records[¶](#user-records "Permalink to this headline")

`UserRecord` s returned by methods from `Kreait\Firebase\Contract\Auth` class have the

following signature:

```

{

 "uid": "jEazVdPDhqec0tnEOG7vM5wbDyU2",

 "email": "user@domain.tld",

 "emailVerified": true,

 "displayName": null,

 "photoUrl": null,

 "phoneNumber": null,

 "disabled": false,

 "metadata": {

 "createdAt": "2018-02-14T15:41:32+00:00",

 "lastLoginAt": "2018-02-14T15:41:32+00:00",

 "passwordUpdatedAt": "2018-02-14T15:42:19+00:00",

 "lastRefreshAt": "2018-02-14T15:42:19+00:00"

 },

 "providerData": [

 {

 "uid": "user@domain.tld",

 "displayName": null,

 "screenName": null,

 "email": "user@domain.tld",

 "photoUrl": null,

 "providerId": "password",

 "phoneNumber": null

 }

 ],

 "passwordHash": "UkVEQUNURUQ=",

 "customClaims": null,

 "tokensValidAfterTime": "2018-02-14T15:41:32+00:00"

}

```

#### List users[¶](#list-users "Permalink to this headline")

To enhance performance and prevent memory issues when retrieving a huge amount of users,

this methods returns a [Generator](http://php.net/manual/en/language.generators.overview.php).

```

$users = $auth->listUsers($defaultMaxResults = 1000, $defaultBatchSize = 1000);

foreach ($users as $user) {

    /\*\* @var \Kreait\Firebase\Auth\UserRecord $user \*/

    // ...

}

// or

array\_map(function (\Kreait\Firebase\Auth\UserRecord $user) {

    // ...

}, iterator\_to\_array($users));

```

#### Query users[¶](#query-users "Permalink to this headline")

Listing all users with `listUser()` is fast an memory-efficient if you want to process a large

number of users. However, if you prefer paginating over subsets of users with more parameters,

you can use the `queryUsers()` method.

User queries can be created in two ways: by building a `UserQuery` object or by passing an array.

The following two snippets show all possible query modifiers with both ways:

```

use Kreait\Firebase\Auth\UserQuery;

# Building a user query object

$userQuery = UserQuery::all()

    ->sortedBy(UserQuery::FIELD\_USER\_EMAIL)

    ->inDescendingOrder()

    // ->inAscendingOrder() # this is the default

    ->withOffset(1)

    ->withLimit(499); # The maximum supported limit is 500

# Using an array

$userQuery = [

    'sortBy' => UserQuery::FIELD\_USER\_EMAIL,

    'order' => UserQuery::ORDER\_DESC,

    // 'order' => UserQuery::ORDER\_DESC # this is the default

    'offset' => 1,

    'limit' => 499, # The maximum supported limit is 500

];

```

It is possible to sort by the following fields:

* `UserQuery::FIELD\_CREATED\_AT`

* `UserQuery::FIELD\_LAST\_LOGIN\_AT`

* `UserQuery::FIELD\_NAME`

* `UserQuery::FIELD\_USER\_EMAIL`

* `UserQuery::FIELD\_USER\_ID`

```

$users = $auth->queryUsers($userQuery);

```

You can also filter by email, phone number or uid:

```

use Kreait\Firebase\Auth\UserQuery;

$userQuery = UserQuery::all()->withFilter(UserQuery::FILTER\_EMAIL, '<email>');

$userQuery = UserQuery::all()->withFilter(UserQuery::FILTER\_PHONE\_NUMBER, '<phone number>');

$userQuery = UserQuery::all()->withFilter(UserQuery::FILTER\_UID, '<uid>');

$userQuery = ['filter' => [UserQuery::FILTER\_EMAIL => '<email>'];

$userQuery = ['filter' => [UserQuery::FILTER\_PHONE\_NUMBER => '<email>'];

$userQuery = ['filter' => [UserQuery::FILTER\_UID => '<email>'];

```

A user query will always return an array of `UserRecord` s. If none could be found, the array

will be empty.

Note

Filters don’t support partial matches, and only one filter can be applied at the same time.

If you specify multiple filters, only the last one will be submitted.

#### Get information about a specific user[¶](#get-information-about-a-specific-user "Permalink to this headline")

```

try {

    $user = $auth->getUser('some-uid');

    $user = $auth->getUserByEmail('user@domain.tld');

    $user = $auth->getUserByPhoneNumber('+49-123-456789');

} catch (\Kreait\Firebase\Exception\Auth\UserNotFound $e) {

    echo $e->getMessage();

}

```

#### Get information about multiple users[¶](#get-information-about-multiple-users "Permalink to this headline")

You can retrieve multiple user records by using `$auth->getUsers()`. When a user doesn’t exist,

no exception is thrown, but its entry in the result set is null:

```

$users = $auth->getUsers(['some-uid', 'another-uid', 'non-existing-uid']);

```

Result:

```

[

   'some-uid' => <UserRecord>,

   'another-uid' => <UserRecord>,

   'non-existing-uid' => null

]

```

#### Create a user[¶](#create-a-user "Permalink to this headline")

The Admin SDK provides a method that allows you to create a new Firebase Authentication user.

This method accepts an object containing the profile information to include in the newly created user account:

```

$userProperties = [

    'email' => 'user@example.com',

    'emailVerified' => false,

    'phoneNumber' => '+15555550100',

    'password' => 'secretPassword',

    'displayName' => 'John Doe',

    'photoUrl' => 'http://www.example.com/12345678/photo.png',

    'disabled' => false,

];

$createdUser = $auth->createUser($userProperties);

// This is equivalent to:

$request = \Kreait\Auth\Request\CreateUser::new()

    ->withUnverifiedEmail('user@example.com')

    ->withPhoneNumber('+15555550100')

    ->withClearTextPassword('secretPassword')

    ->withDisplayName('John Doe')

    ->withPhotoUrl('http://www.example.com/12345678/photo.png');

$createdUser = $auth->createUser($request);

```

By default, Firebase Authentication will generate a random uid for the new user.

If you instead want to specify your own uid for the new user, you can include

in the properties passed to the user creation method:

```

$properties = [

    'uid' => 'some-uid',

    // other properties

];

$request = \Kreait\Auth\Request\CreateUser::new()

    ->withUid('some-uid')

    // with other properties

;

```

Any combination of the following properties can be provided:

| Property | Type | Description |

| --- | --- | --- |

| `uid` | string | The uid to assign to the newly created user. Must be a string between 1 and 128 characters long, inclusive. If not provided, a random uid will be automatically generated. |

| `email` | string | The user’s primary email. Must be a valid email address. |

| `emailVerified` | boolean | Whether or not the user’s primary email is verified. If not provided, the default is false. |

| `phoneNumber` | string | The user’s primary phone number. Must be a valid E.164 spec compliant phone number. |

| `password` | string | The user’s raw, unhashed password. Must be at least six characters long. |

| `displayName` | string | The users’ display name. |

| `photoURL` | string | The user’s photo URL. |

| `disabled` | boolean | Whether or not the user is disabled. true for disabled; false for enabled. If not provided, the default is false. |

Note

All of the above properties are optional. If a certain property is not specified,

the value for that property will be empty unless a default is mentioned

in the above table.

Note

If you provide none of the properties, an anonymous user will be created.

#### Update a user[¶](#update-a-user "Permalink to this headline")

Updating a user works exactly as creating a new user, except that the `uid` property is required:

```

$uid = 'some-uid';

$properties = [

    'displayName' => 'New display name'

];

$updatedUser = $auth->updateUser($uid, $properties);

$request = \Kreait\Auth\Request\UpdateUser::new()

    ->withDisplayName('New display name');

$updatedUser = $auth->updateUser($uid, $request);

```

In addition to the properties of a create request, the following properties can be provided:

| Property | Type | Description |

| --- | --- | --- |

| `deleteEmail` | boolean | Whether or not to delete the user’s email. |

| `deletePhotoUrl` | boolean | Whether or not to delete the user’s photo. |

| `deleteDisplayName` | boolean | Whether or not to delete the user’s display name. |

| `deletePhoneNumber` | boolean | Whether or not to delete the user’s phone number. |

| `deleteProvider` | string|array | One or more identity providers to delete. |

| `customAttributes` | array | A list of custom attributes which will be available in a User’s ID token. |

Note

When deleting the email from an existing user, the password authentication provider

will be disabled (the user can’t log in with an email and password combination

anymore). After adding a new email to the same user, the previously set password

might be restored. If you just want to change a user’s email, consider updating

the email field directly.

#### Change a user’s password[¶](#change-a-user-s-password "Permalink to this headline")

```

$uid = 'some-uid';

$updatedUser = $auth->changeUserPassword($uid, 'new password');

```

#### Change a user’s email[¶](#change-a-user-s-email "Permalink to this headline")

```

$uid = 'some-uid';

$updatedUser = $auth->changeUserEmail($uid, 'user@domain.tld');

```

#### Disable a user[¶](#disable-a-user "Permalink to this headline")

```

$uid = 'some-uid';

$updatedUser = $auth->disableUser($uid);

```

#### Enable a user[¶](#enable-a-user "Permalink to this headline")

```

$uid = 'some-uid';

$updatedUser = $auth->enableUser($uid);

```

#### Custom user claims[¶](#custom-user-claims "Permalink to this headline")

Note

Learn more about custom attributes/claims in the official documentation:

[Control Access with Custom Claims and Security Rules](https://firebase.google.com/docs/auth/admin/custom-claims)

```

// The new custom claims will propagate to the user's ID token the

// next time a new one is issued.

$auth->setCustomUserClaims($uid, ['admin' => true, 'key1' => 'value1']);

// Retrieve a user's current custom claims

$claims = $auth->getUser($uid)->customClaims;

// Remove a user's custom claims

$auth->setCustomUserClaims($uid, null);

```

The custom claims object should not contain any [OIDC](http://openid.net/specs/openid-connect-core-1_0.html#IDToken)

reserved key names or Firebase reserved names. Custom claims payload must not exceed 1000 bytes.

#### Delete a user[¶](#delete-a-user "Permalink to this headline")

The Firebase Admin SDK allows deleting users by their `uid`:

```

$uid = 'some-uid';

try {

    $auth->deleteUser($uid);

catch (\Kreait\Firebase\Exception\Auth\UserNotFound $e) {

    echo $e->getMessage();

} catch (\Kreait\Firebase\Exception\AuthException $e) {

    echo 'Deleting

}

```

This method returns nothing when the deletion completes successfully. If the provided `uid` does not correspond

to an existing user or the user cannot be deleted for any other reason, the delete user method throws an error.

#### Delete multiple users[¶](#delete-multiple-users "Permalink to this headline")

The Firebase Admin SDK can also delete multiple (up to 1000) users at once:

```

$uid = ['uid-1', 'uid-2', 'uid-3'];

$forceDeleteEnabledUsers = true; // default: false

$result = $auth->deleteUsers($uids, $forceDeleteEnabledUsers);

```

By default, only disabled users will be deleted. If you want to also delete enabled users,

use `true` as the second argument.

This method always returns an instance of `Kreait\Firebase\Auth\DeleteUsersResult`:

```

$successCount = $result->successCount();

$failureCount = $result->failureCount();

$errors = $result->rawErrors();

```

Note

Using this method to delete multiple users at once will not trigger `onDelete()` event handlers for

Cloud Functions for Firebase. This is because batch deletes do not trigger a user deletion event on each user.

Delete users one at a time if you want user deletion events to fire for each deleted user.

#### Using Email Action Codes[¶](#using-email-action-codes "Permalink to this headline")

The Firebase Admin SDK provides the ability to send users emails containing links they can use for password resets,

email address verification, and email-based sign-in. These emails are sent by Google and have limited

customizability.

If you want to instead use your own email templates and your own email delivery service, you can use the

Firebase Admin SDK to programmatically generate the action links for the above flows, which you can

include in emails to your users.

##### Action Code Settings[¶](#action-code-settings "Permalink to this headline")

Note

Action Code Settings are optional.

Action Code Settings allow you to pass additional state via a continue URL which is accessible after the user clicks

the email link. This also provides the user the ability to go back to the app after the action is completed.

In addition, you can specify whether to handle the email action link directly from a mobile application

when it is installed or from a browser.

For links that are meant to be opened via a mobile app, you’ll need to enable Firebase Dynamic Links and perform some

tasks to detect these links from your mobile app. Refer to the instructions on how to

[configure Firebase Dynamic Links](https://firebase.google.com/docs/auth/web/passing-state-in-email-actions#configuring_firebase_dynamic_links)

for email actions.

| Parameter | Type | Description |

| --- | --- | --- |

| `continueUrl` | string|null | Sets the continue URL |

| `url` | string|null | Alias for `continueUrl` |

| `handleCodeInApp` | bool|null | 

Whether the email action link will be opened in a mobile app or a web link first.

The default is false. When set to true, the action code link will be be sent

as a Universal Link or Android App Link and will be opened by the app if

installed. In the false case, the code will be sent to the web widget first

and then on continue will redirect to the app if installed.

 |

| `androidPackageName` | string|null | 

Sets the Android package name. This will try to open the link in an android app

if it is installed.

 |

| `androidInstallApp` | bool|null | 

Whether to install the Android app if the device supports it and the app is not

already installed. If this field is provided without a `androidPackageName`,

an error is thrown explaining that the packageName must be provided in

conjunction with this field.

 |

| `androidMinimumVersion` | string|null | 

If specified, and an older version of the app is installed,

the user is taken to the Play Store to upgrade the app.

The Android app needs to be registered in the Console.

 |

| `iOSBundleId` | string|null | 

Sets the iOS bundle ID. This will try to open the link in an iOS app if it is

installed. The iOS app needs to be registered in the Console.

 |

Example:

```

$actionCodeSettings = [

    'continueUrl' => 'https://www.example.com/checkout?cartId=1234',

    'handleCodeInApp' => true,

    'dynamicLinkDomain' => 'coolapp.page.link',

    'androidPackageName' => 'com.example.android',

    'androidMinimumVersion' => '12',

    'androidInstallApp' => true,

    'iOSBundleId' => 'com.example.ios',

];

```

##### Email verification[¶](#email-verification "Permalink to this headline")

To generate an email verification link, provide the existing user’s unverified email and optional Action Code Settings.

The email used must belong to an existing user. Depending on the method you use, an email will be sent to the user,

or you will get an email action link that you can use in a custom email.

```

$link = $auth->getEmailVerificationLink($email);

$link = $auth->getEmailVerificationLink($email, $actionCodeSettings);

$link = $auth->getEmailVerificationLink($email, $actionCodeSettings, $locale);

$auth->sendEmailVerificationLink($email);

$auth->sendEmailVerificationLink($email, $actionCodeSettings);

$auth->sendEmailVerificationLink($email, null, $locale);

$auth->sendEmailVerificationLink($email, $actionCodeSettings, $locale);

```

##### Password reset[¶](#password-reset "Permalink to this headline")

To generate a password reset link, provide the existing user’s email and optional Action Code Settings.

The email used must belong to an existing user. Depending on the method you use, an email will be sent to the user,

or you will get an email action link that you can use in a custom email.

```

$link = $auth->getPasswordResetLink($email);

$link = $auth->getPasswordResetLink($email, $actionCodeSettings);

$link = $auth->getPasswordResetLink($email, $actionCodeSettings, $locale);

$auth->sendPasswordResetLink($email);

$auth->sendPasswordResetLink($email, $actionCodeSettings);

$auth->sendPasswordResetLink($email, null, $locale);

$auth->sendPasswordResetLink($email, $actionCodeSettings, $locale);

```

##### Email link for sign-in[¶](#email-link-for-sign-in "Permalink to this headline")

Note

Before you can authenticate users with email link sign-in, you will need to enable

[email link sign-in](https://firebase.google.com/docs/auth/web/email-link-auth#enable_email_link_sign-in_for_your_firebase_project)

for your Firebase project.

Note

Unlike password reset and email verification, the email used does not necessarily need to belong to an existing user,

as this operation can be used to sign up new users into your app via email link.

Note

The ActionCodeSettings object is required in this case to provide information on where to return the user after the

link is clicked for sign-in completion.

To generate a sign-in link, provide the user’s email and Action Code Settings. Depending on the method you use,

an email will be sent to the user, or you will get an email action link that you can use in a custom email.

```

$link = $auth->getSignInWithEmailLink($email, $actionCodeSettings);

$auth->sendSignInWithEmailLink($email, $actionCodeSettings);

$auth->sendSignInWithEmailLink($email, $actionCodeSettings, $locale);

```

##### Confirm a password reset[¶](#confirm-a-password-reset "Permalink to this headline")

Note

Out of the box, Firebase handles the confirmation of password reset requests. You can use your own

server to handle account management emails by following the instructions on

[Customize account management emails and SMS messages](https://support.google.com/firebase/answer/7000714)

```

$oobCode = '...'; // Extract the OOB code from the request url (not scope of the SDK (yet :)))

$newPassword = '...';

$invalidatePreviousSessions = true; // default, will revoke current user refresh tokens

try {

    $auth->confirmPasswordReset($oobCode, $newPassword, $invalidatePreviousSessions);

} catch (\Kreait\Firebase\Exception\Auth\ExpiredOobCode $e) {

    // Handle the case of an expired reset code

} catch (\Kreait\Firebase\Exception\Auth\InvalidOobCode $e) {

    // Handle the case of an invalid reset code

} catch (\Kreait\Firebase\Exception\AuthException $e) {

    // Another error has occurred

}

```

### Dynamic Links[¶](#dynamic-links "Permalink to this headline")

You can create short Dynamic Links with the Firebase Admin SDK for PHP. Dynamic Links can be

* a long Dynamic Link

* an array containing Dynamic Link parameters

* an action created with builder methods

and will return a URL like `https://example.page.link/wXYZ`.

Note

Short Dynamic Links created via the REST API or this SDK do not show up in the Firebase console. Such Dynamic Links

are intended for user-to-user sharing. For marketing use cases, continue to create your links directly through the

[Dynamic Links page](https://console.firebase.google.com/project/_/durablelinks/) of the Firebase console.

Before you start, please read about Dynamic Links in the official documentation:

* [Dynamic Links Product Page](https://firebase.google.com/products/dynamic-links/)

* [Create Dynamic Links with the REST API](https://firebase.google.com/docs/dynamic-links/rest)

* [Long Dynamic Links](https://firebase.google.com/docs/dynamic-links/create-manually)

* [Dynamic Link API Reference](https://firebase.google.com/docs/reference/dynamic-links/link-shortener)

#### Getting started[¶](#getting-started "Permalink to this headline")

* In the Firebase console, open the

[Dynamic Links](https://console.firebase.google.com/u/1/project/_/durablelinks/links/) section.

* If you have not already accepted the terms of service and set a domain for your Dynamic Links, do so when prompted.

* If you already have a Dynamic Links domain, take note of it. You need to provide a Dynamic Links Domain when you

programmatically create Dynamic Links.

#### Initializing the Dynamic Links component[¶](#initializing-the-dynamic-links-component "Permalink to this headline")

**With the SDK**

```

$dynamicLinksDomain = 'https://example.page.link';

$dynamicLinks = $factory->createDynamicLinksService($dynamicLinksDomain);

```

**With Dependency Injection** ([Symfony Bundle](https://github.com/kreait/firebase-bundle)/[Laravel/Lumen Package](https://github.com/kreait/laravel-firebase))

To define the default Dynamic Links Domain for **Laravel**, configure the `FIREBASE\_DYNAMIC\_LINKS\_DEFAULT\_DOMAIN` environment variable.

```

use Kreait\Firebase\Contract\DynamicLinks;

class MyService

{

    public function \_\_construct(DynamicLinks $dynamicLinks)

    {

        $this->dynamicLinks = $dynamicLinks;

    }

}

```

**With the Laravel** `app()` **helper** ([Laravel/Lumen Package](https://github.com/kreait/laravel-firebase))

To define the default Dynamic Links Domain, configure the `FIREBASE\_DYNAMIC\_LINKS\_DEFAULT\_DOMAIN` environment variable.

```

$dynamicLinks = app('firebase.dynamic\_links');

```

#### Create a Dynamic Link[¶](#create-a-dynamic-link "Permalink to this headline")

You can create a Dynamic Link by using one of the methods below. Each method will return an instance of

`Kreait\Firebase\DynamicLink`.

```

use use Kreait\Firebase\DynamicLink\CreateDynamicLink\FailedToCreateDynamicLink;

$url = 'https://www.example.com/some/path';

try {

    $link = $dynamicLinks->createUnguessableLink($url);

    $link = $dynamicLinks->createDynamicLink($url, CreateDynamicLink::WITH\_UNGUESSABLE\_SUFFIX);

    $link = $dynamicLinks->createShortLink($url);

    $link = $dynamicLinks->createDynamicLink($url, CreateDynamicLink::WITH\_SHORT\_SUFFIX);

} catch (FailedToCreateDynamicLink $e) {

    echo $e->getMessage(); exit;

}

```

If `createDynamicLink()` is called without a second parameter, the Dynamic Link is created with an unguessable suffix.

Unguessable suffixes have a length of 17 characters, short suffixes a length of 4 characters. You can learn more about

the length of Dynamic Links in the

[official documentation](https://firebase.google.com/docs/dynamic-links/rest#set_the_length_of_a_short).

The returned object will be an instance of `Kreait\Firebase\DynamicLink` with the following accessors:

```

$link->uri();         // Psr\Http\Message\UriInterface

$link->previewUri();  // Psr\Http\Message\UriInterface

$link->domain();      // string

$link->suffix();      // string

$link->hasWarnings(); // bool

$link->warnings();    // array

$uriString = (string) $link;

```

#### Create a short link from a long link[¶](#create-a-short-link-from-a-long-link "Permalink to this headline")

If you have a [manually constructed link](https://firebase.google.com/docs/dynamic-links/create-manually),

you can convert it to a short link:

```

use Kreait\Firebase\DynamicLink\ShortenLongDynamicLink\FailedToShortenLongDynamicLink;

$longLink = 'https://example.page.link?link=https://domain.tld/some/path';

try {

    $link = $dynamicLinks->shortenLongDynamicLink($longLink);

    $link = $dynamicLinks->shortenLongDynamicLink($longLink, ShortenLongDynamicLink::WITH\_UNGUESSABLE\_SUFFIX);

    $link = $dynamicLinks->shortenLongDynamicLink($longLink, ShortenLongDynamicLink::WITH\_SHORT\_SUFFIX);

} catch (FailedToShortenLongDynamicLink $e) {

    echo $e->getMessage(); exit;

}

```

If `shortenLongDynamicLink()` is called without a second parameter, the Dynamic Link is created with an unguessable suffix.

#### Get link statistics[¶](#get-link-statistics "Permalink to this headline")

You can use this REST API to get analytics data for each of your short Dynamic Links, whether created in the console

or programmatically.

Note

These statistics might not include events that have been logged within the last 36 hours.

```

use Kreait\Firebase\DynamicLink\GetStatisticsForDynamicLink\FailedToGetStatisticsForDynamicLink;

try {

    $stats = $dynamicLinks->getStatistics('https://example.page.link/wXYZ');

    $stats = $dynamicLinks->getStatistics('https://example.page.link/wXYZ', 14); // duration in days

} catch (FailedToGetStatisticsForDynamicLink $e) {

    echo $e->getMessage(); exit;

}

```

If `getStatistics()` is called without a second parameter, stats will include the statistics of the past 7 days.

The returned object will be an instance of `Kreait\Firebase\DynamicLink\DynamicLinkStatistics`, which currently

only includes event statistics. You can access the raw returned data with $stats->rawData().

##### Event Statistics[¶](#event-statistics "Permalink to this headline")

Firebase Dynamic Links tracks the number of times each of your short Dynamic Links have been clicked, as well as the

number of times a click resulted in a redirect, app install, app first-open, or app re-open, including the platform

on which that event occurred.

Each of the following methods returns a (filtered) instance of `Kreait\Firebase\DynamicLink\EventStatistics` which

supports any combination of filters and is countable with `count()` or `->count()` as shown below:

```

$eventStats = $stats->eventStatistics();

$allClicks = $eventStats->clicks();

$allRedirects = $eventStats->redirects();

$allAppInstalls = $eventStats->appInstalls();

$allAppFirstOpens = $eventStats->appFirstOpens();

$allAppReOpens = $eventStats->appReOpens();

$allAndroidEvents = $eventStats->onAndroid();

$allDesktopEvents = $eventStats->onDesktop();

$allIOSEvents = $eventStats->onIOS();

$clicksOnDesktop = $eventStats->clicks()->onDesktop();

$appInstallsOnAndroid = $eventStats->onAndroid()->appInstalls();

$appReOpensOnIOS = $eventStats->appReOpens()->onIOS();

$totalAmountOfClicks = count($eventStats->clicks());

$totalAmountOfAppFirstOpensOnAndroid = $eventStats->appFirstOpens()->onAndroid()->count();

$custom = $eventStats->filter(function (array $eventGroup) {

    return $eventGroup['platform'] === 'CUSTOM\_PLATFORM\_THAT\_THE\_SDK\_DOES\_NOT\_KNOW\_YET';

});

```

#### Advanced usage[¶](#advanced-usage "Permalink to this headline")

##### Using actions[¶](#using-actions "Permalink to this headline")

You can fully customize the creation of Dynamic Links by building up a `Kreait\Firebase\DynamicLink\CreateDynamicLink`

action. The following code shows all available building components:

```

use Kreait\Firebase\DynamicLink\CreateDynamicLink;

$action = CreateDynamicLink::forUrl($url)

    ->withDynamicLinkDomain('https://example.page.link')

    ->withUnguessableSuffix() // default

    // or

    ->withShortSuffix()

    ->withAnalyticsInfo(

        AnalyticsInfo::new()

            ->withGooglePlayAnalyticsInfo(

                GooglePlayAnalytics::new()

                    ->withGclid('gclid')

                    ->withUtmCampaign('utmCampaign')

                    ->withUtmContent('utmContent')

                    ->withUtmMedium('utmMedium')

                    ->withUtmSource('utmSource')

                    ->withUtmTerm('utmTerm')

            )

            ->withItunesConnectAnalytics(

                ITunesConnectAnalytics::new()

                    ->withAffiliateToken('affiliateToken')

                    ->withCampaignToken('campaignToken')

                    ->withMediaType('8')

                    ->withProviderToken('providerToken')

            )

    )

    ->withNavigationInfo(

        NavigationInfo::new()

            ->withoutForcedRedirect() // default

            // or

            ->withForcedRedirect()

    )

    ->withIOSInfo(

        IOSInfo::new()

            ->withAppStoreId('appStoreId')

            ->withBundleId('bundleId')

            ->withCustomScheme('customScheme')

            ->withFallbackLink('https://fallback.domain.tld')

            ->withIPadBundleId('iPadBundleId')

            ->withIPadFallbackLink('https://ipad-fallback.domain.tld')

    )

    ->withAndroidInfo(

        AndroidInfo::new()

            ->withFallbackLink('https://fallback.domain.tld')

            ->withPackageName('packageName')

            ->withMinPackageVersionCode('minPackageVersionCode')

    )

    ->withSocialMetaTagInfo(

        SocialMetaTagInfo::new()

            ->withDescription('Social Meta Tag description')

            ->withTitle('Social Meta Tag title')

            ->withImageLink('https://domain.tld/image.jpg')

    );

$link = $dynamicLinks->createDynamicLink($action);

```

##### Using parameter arrays[¶](#using-parameter-arrays "Permalink to this headline")

If you prefer using a parameter array to configure a Dynamic Link, or if this SDK doesn’t yet have support for a

given new option, you can pass an array to the `createDynamicLink()` method. As the parameters will not be processed

or validated by the SDK, you have to make sure that the parameter structure matches the one described in the

[API Reference Documentation](https://firebase.google.com/docs/reference/dynamic-links/link-shortener)

```

use use Kreait\Firebase\DynamicLink\CreateDynamicLink\FailedToCreateDynamicLink;

$parameters = [

    'dynamicLinkInfo' => [

        'domainUriPrefix' => 'https://example.page.link',

        'link' => 'https://domain.tld/some/path',

    ],

    'suffix' => ['option' => 'SHORT'],

];

try {

    $link = $dynamicLinks->createDynamicLink($parameters);

} catch (FailedToCreateDynamicLink $e) {

    echo $e->getMessage(); exit;

}

```

### Remote Config[¶](#remote-config "Permalink to this headline")

Change the behavior and appearance of your app without publishing an app update.

Firebase Remote Config is a cloud service that lets you change the behavior and appearance of your app without

requiring users to download an app update. When using Remote Config, you create in-app default values that

control the behavior and appearance of your app.

Before you start, please read about Firebase Remote Config in the official documentation:

* [Firebase Remote Config](https://firebase.google.com/docs/remote-config/)

#### Before you begin[¶](#before-you-begin "Permalink to this headline")

For Firebase projects created before the March 7, 2018 release of the Remote Config REST API, you must enable the API in the Google APIs console.

1. Open the [Firebase Remote Config API page](https://console.developers.google.com/apis/api/firebaseremoteconfig.googleapis.com/overview?project=_) in the Google APIs console.

2. When prompted, select your Firebase project. (Every Firebase project has a corresponding project in the Google APIs console.)

3. Click Enable on the Firebase Remote Config API page.

#### Initializing the Realtime Database component[¶](#initializing-the-realtime-database-component "Permalink to this headline")

**With the SDK**

```

$remoteConfig = $factory->createRemoteConfig();

```

**With Dependency Injection** ([Symfony Bundle](https://github.com/kreait/firebase-bundle)/[Laravel/Lumen Package](https://github.com/kreait/laravel-firebase))

```

use Kreait\Firebase\Contract\RemoteConfig;

class MyService

{

    public function \_\_construct(RemoteConfig $remoteConfig)

    {

        $this->remoteConfig = $remoteConfig;

    }

}

```

**With the Laravel** `app()` **helper** ([Laravel/Lumen Package](https://github.com/kreait/laravel-firebase))

```

$remoteConfig = app('firebase.remote\_config');

```

#### Get the Remote Config[¶](#get-the-remote-config "Permalink to this headline")

```

$template = $remoteConfig->get(); // Returns a Kreait\Firebase\RemoteConfig\Template

$version = $template->version(); // Returns a Kreait\Firebase\RemoteConfig\Version

```

#### Create a new Remote Config[¶](#create-a-new-remote-config "Permalink to this headline")

```

use Kreait\Firebase\RemoteConfig;

$template = RemoteConfig\Template::new();

```

#### Add a condition[¶](#add-a-condition "Permalink to this headline")

```

use Kreait\Firebase\RemoteConfig;

$germanLanguageCondition = RemoteConfig\Condition::named('lang\_german')

    ->withExpression("device.language in ['de', 'de\_AT', 'de\_CH']")

    ->withTagColor(TagColor::ORANGE); // The TagColor is optional

$frenchLanguageCondition = Condition::named('lang\_french')

    ->withExpression("device.language in ['fr', 'fr\_CA', 'fr\_CH']")

    ->withTagColor(TagColor::GREEN);

$template = $template

    ->withCondition($germanLanguageCondition)

    ->withCondition($frenchLanguageCondition)

;

$conditionNames = $template->conditionNames();

// Returns ['lang\_german', 'lang\_french']

```

#### Add a parameter[¶](#add-a-parameter "Permalink to this headline")

```

use Kreait\Firebase\RemoteConfig;

$welcomeMessageParameter = RemoteConfig\Parameter::named('welcome\_message')

        ->withDefaultValue('Welcome!')

        ->withDescription('This is a welcome message') // optional

;

```

#### Conditional values[¶](#conditional-values "Permalink to this headline")

```

use Kreait\Firebase\RemoteConfig;

$germanLanguageCondition = RemoteConfig\Condition::named('lang\_german')

    ->withExpression("device.language in ['de', 'de\_AT', 'de\_CH']");

$germanWelcomeMessage = RemoteConfig\ConditionalValue::basedOn($germanLanguageCondition, 'Willkommen!');

$welcomeMessageParameter = RemoteConfig\Parameter::named('welcome\_message')

        ->withDefaultValue('Welcome!')

        ->withConditionalValue($germanWelcomeMessage);

$template = $template

    ->withCondition($germanLanguageCondition)

    ->withParameter($welcomeMessageParameter);

```

Note

When you use a conditional value, make sure to add the corresponding condition to the template first.

#### Parameter Groups[¶](#parameter-groups "Permalink to this headline")

```

use Kreait\Firebase\RemoteConfig;

$uiColors = RemoteConfig\ParameterGroup::named('UI Colors')

    ->withDescription('Remote configurable UI colors')

    ->withParameter(RemoteConfig\Parameter::named('Primary Color')->withDefaultValue('blue'))

    ->withParameter(RemoteConfig\Parameter::named('Secondary Color')->withDefaultValue('red'))

;

$template = $template->withParameterGroup($parameterGroup);

```

#### Removing Remote Config Elements[¶](#removing-remote-config-elements "Permalink to this headline")

You can remove elements from a Remote Config template with the following methods:

```

$template = Template::new()

    ->withCondition(Condition::named('condition'))

    ->withParameter(Parameter::named('parameter'))

    ->withParameterGroup(ParameterGroup::named('group'))

$template = $template

    ->withRemovedCondition('condition')

    ->withRemovedParameter('parameter')

    ->withRemovedParameterGroup('group');

```

#### Validation[¶](#validation "Permalink to this headline")

Usually, the SDK will protect you from creating an invalid Remote Config template in the first

place. If you want to be sure, you can validate the template with a call to the Firebase API:

```

use Kreait\Firebase\Exception\RemoteConfig\ValidationFailed;

try {

    $remoteConfig->validate($template);

} catch (ValidationFailed $e) {

    echo $e->getMessage();

}

```

Note

The `ValidationFailed` exception extends `Kreait\Firebase\Exception\RemoteConfigException`,

so you can safely use the more generic exception type as well.

#### Publish the Remote Config[¶](#publish-the-remote-config "Permalink to this headline")

```

use Kreait\Firebase\Exception\RemoteConfigException

try {

    $remoteConfig->publish($template);

} catch (RemoteConfigException $e) {

    echo $e->getMessage();

}

```

#### Remote Config history[¶](#remote-config-history "Permalink to this headline")

Since August 23, 2018, Firebase provides a change history for your published Remote configs.

The following properties are available from a `Kreait\Firebase\RemoteConfig\Version` object:

```

$version->versionNumber();

$version->user(); // The user/service account the performed the change

$version->description();

$version->updatedAt();

$version->updateOrigin();

$version->updateType();

$version->rollBackSource();

```

##### List versions[¶](#list-versions "Permalink to this headline")

To enhance performance and prevent memory issues when retrieving a huge amount of versions,

this methods returns a [Generator](http://php.net/manual/en/language.generators.overview.php).

```

foreach ($auth->listVersions() as $version) {

    /\*\* @var \Kreait\Firebase\RemoteConfig\Version $version \*/

    // ...

}

// or

array\_map(function (\Kreait\Firebase\RemoteConfig\Version $version) {

    // ...

}, iterator\_to\_array($auth->listVersions()));

```

##### Filtering[¶](#filtering "Permalink to this headline")

You can filter the results of `RemoteConfig::listVersions()`:

```

use Kreait\Firebase\RemoteConfig\FindVersions;

$query = FindVersions::all()

    // Versions created/updated after August 1st, 2019 at midnight

    ->startingAt(new DateTime('2019-08-01 00:00:00'))

    // Versions created/updated before August 7th, 2019 at the end of the day

    ->endingAt(new DateTime('2019-08-06 23:59:59'))

    // Versions with version numbers smaller than 3464

    ->upToVersion(VersionNumber::fromValue(3463))

    // Setting a page size can results in faster first results,

    // but results in more request

    ->withPageSize(5)

    // Stop querying after the first 10 results

    ->withLimit(10)

;

// Alternative array notation

$query = [

    'startingAt' => '2019-08-01',

    'endingAt' => '2019-08-07',

    'upToVersion' => 9999,

    'pageSize' => 5,

    'limit' => 10,

];

foreach ($remoteConfig->listVersions($query) as $version) {

    echo "Version number: {$version->versionNumber()}\n";

    echo "Last updated at {$version->updatedAt()->format('Y-m-d H:i:s')}\n";

    // ...

    echo "\n---\n";

}

```

##### Get a specific version[¶](#get-a-specific-version "Permalink to this headline")

```

$version = $remoteConfig->getVersion($versionNumber);

```

##### Rollback to a version[¶](#rollback-to-a-version "Permalink to this headline")

```

$template = $remoteConfig->rollbackToVersion($versionNumber);

```

### Framework Integrations[¶](#framework-integrations "Permalink to this headline")

kreait provides and maintains the following framework integrations for the Firebase Admin SDK for PHP:

#### Laravel[¶](#laravel "Permalink to this headline")

[kreait/laravel-firebase](https://github.com/kreait/laravel-firebase)

#### Symfony[¶](#symfony "Permalink to this headline")

[kreait/firebase-bundle](https://github.com/kreait/firebase-bundle)

#### CodeIgniter[¶](#codeigniter "Permalink to this headline")

[tatter/firebase](https://github.com/tattersoftware/codeigniter4-firebase)

### Testing and Local Development[¶](#testing-and-local-development "Permalink to this headline")

#### Integration Tests[¶](#integration-tests "Permalink to this headline")

The most reliable way of testing your project is to create a separate Firebase project and configure your tests to

use it instead of the your production project. For example, you could have multiple Firebase projects depending on

your use-case:

> 

> * `my-project-dev`: used for developers while they develop new features

> * `my-project-int`: use by CI/CD pipelines

> * `my-project-staging`: used to present upcoming to stake holders

> * `my-project`: used for production

> 

> 

> 

#### Using the Firebase Emulator Suite[¶](#using-the-firebase-emulator-suite "Permalink to this headline")

For an introduction to the Firebase Emulator suite, please visit the official documentation:

<https://firebase.google.com/docs/emulator-suite>

Warning

Only the Auth and Realtime Database Emulators are currently supported in this PHP SDK.

To use the Firebase Emulator Suite, you must first [install it](https://firebase.google.com/docs/cli).

See the [official documentation](https://firebase.google.com/docs/emulator-suite/install_and_configure#startup)

for instructions how to work with it.

The emulator suite must be running otherwise the PHP SDK can’t connect to it.

##### Auth Emulator[¶](#auth-emulator "Permalink to this headline")

If not already present, create a firebase.json file in the root of your project and make sure that at least the

following fields are set (the port number can be changed to your requirements):

```

{

 "emulators": {

 "auth": {

 "port": 9099

 }

 }

}

```

Firebase Admin SDKs automatically connect to the Authentication emulator when the

`FIREBASE\_AUTH\_EMULATOR\_HOST` environment variable is set.

```

$ export FIREBASE\_AUTH\_EMULATOR\_HOST="localhost:9099"

```

With the environment variable set, Firebase Admin SDKs will accept unsigned ID Tokens and session cookies issued by the

Authentication emulator (via `verifyIdToken` and `createSessionCookie` methods respectively) to facilitate local

development and testing. Please make sure not to set the environment variable in production.

When connecting to the Authentication emulator, you will need to specify a project ID. You can pass a project ID to

the Factory directly or set the `GOOGLE\_CLOUD\_PROJECT` environment variable. Note that you do not need to use your

real Firebase project ID; the Authentication emulator will accept any project ID.

##### Realtime Database Emulator[¶](#realtime-database-emulator "Permalink to this headline")

If not already present, create a firebase.json file in the root of your project and make sure that at least the

following fields are set (the port number can be changed to your requirements):

```

{

 "emulators": {

 "database": {

 "port": 9100

 }

 }

}

```

Note

The Realtime Database Emulator uses port `9000` by default. This port is also used by PHP-FPM, so it is

recommended to chose one that differs to not run into conflicts.

Firebase Admin SDKs automatically connect to the Realtime Database emulator when the

`FIREBASE\_DATABASE\_EMULATOR\_HOST` environment variable is set.

```

$ export FIREBASE\_DATABASE\_EMULATOR\_HOST="localhost:9100"

```

### Tutorials[¶](#tutorials "Permalink to this headline")

You can find an example project implementing the Firebase Admin SDK for PHP at

<https://github.com/jeromegamez/firebase-php-examples> .

In addition, the SDK has been featured in the following tutorials.

Warning

Articles and videos prefixed with `[4.x]` are targeted at Release 4.x of the SDK.

Processes and method names can be different in the current release.

Please look at the current documentation and adapt your code accordingly.

#### Articles[¶](#articles "Permalink to this headline")

* **[4.x]** [How to integrate Laravel with Google Firebase](https://medium.com/@javinunez/how-to-integrate-laravel-with-google-firebase-512188adae13)

by [Javier Núñez](https://twitter.com/javiernunezfdez) (English, April 2019)

* **[4.x]** [Integrate Firebase With PHP and Optimize Your Real Time Communication](https://www.cloudways.com/blog/php-firebase-integration/)

by [Shahroze Nawaz](https://twitter.com/_shahroznawaz) (English, November 2018)

* **[4.x]** [Connect Laravel with Firebase Real Time Database](https://www.cloudways.com/blog/firebase-realtime-database-laravel/)

by [Pardeep Kumar](https://twitter.com/Pardip_Trivedi) (English, March 2018)

#### Videos[¶](#videos "Permalink to this headline")

* **[4.x]** [Firebase for Web | PHP Tutorial](https://youtu.be/jUIDEVzJ4MU) by [Umar Hameed](https://twitter.com/umarhameedd) (Hindi/Urdu, January 2019)

* **[4.x]** [Firebase and PHP](https://youtu.be/3ACxp56r7ag) by [Arthur Mann](https://twitter.com/ArthiMann) (English, August 2018)

Note

Do you know another tutorial that is not featured in this list? Then please consider adding it

by [creating a Pull Request in the GitHub Repository of this project](https://github.com/kreait/firebase-php).

### Troubleshooting[¶](#troubleshooting "Permalink to this headline")

Note

This SDK works with immutable objects until noted otherwise. You can recognize these

objects when they have a ˚`with\*``method. In that case, please keep in mind that in

order to get hold of the changes you made, you will have to use the result of

that method, e.g. `$changedObject = $object->withChangedProperty();`.

#### Error handling[¶](#error-handling "Permalink to this headline")

In general, if executing a method from the SDK doesn’t throw an error, it is safe to assume that the

requested operation has worked according to the motto “no news is good news”. If you do get an error,

it is good practice to wrap the problematic code in a try/catch (*try* an operation and handle

possible errors by *catch* ing them):

```

use Kreait\Firebase\Exception\FirebaseException;

use Throwable;

try {

    // The operation you want to perform

    echo 'OK';

} catch (FirebaseException $e} {

    echo 'An error has occurred while working with the SDK: '.$e->getMessage;

} catch (Throwable $e) {

    echo 'A not-Firebase specific error has occurred: '.$e->getMessage;

}

```

This is especially useful when you encounter `Fatal error: Uncaught GuzzleHttp\Exception\ClientException`

errors which are caused by the Google/Firebase APIs rejecting a request. Those errors are handled by the

SDK and should be converted to instances of `Kreait\Firebase\Exception\FirebaseException`.

If you want to be sure to catch *any* error, catch `Throwable`.

#### Call to private/undefined method …[¶](#call-to-private-undefined-method "Permalink to this headline")

If you receive an error like

```

Fatal error: Uncaught Error: Call to private method Kreait\Firebase\ServiceAccount::fromJsonFile()

```

you have most likely followed a tutorial that is targeted at Version 4.x of this release and have code

that looks like this:

```

$serviceAccount = ServiceAccount::fromJsonFile(\_\_DIR\_\_.'/google-service-account.json');

$firebase = (new Factory)

    ->withServiceAccount($serviceAccount)

    ->create();

$database = $firebase->getDatabase();

```

Change it to the following:

```

$factory = (new Factory)->withServiceAccount(\_\_DIR\_\_.'/google-service-account.json');

$database = $factory->createDatabase();

```

#### PHP Parse Error/PHP Syntax Error[¶](#php-parse-error-php-syntax-error "Permalink to this headline")

If you’re getting an error in the likes of

```

PHP Parse error: syntax error, unexpected ':', expecting ';' or '{' in ...

```

the environment you are running the script in does not use PHP 7.x. You can check this

by adding the line

```

echo phpversion(); exit;

```

somewhere in your script.

#### Class ‘Kreait\Firebase\ …’ not found[¶](#class-kreait-firebase-not-found "Permalink to this headline")

You are probably not using the latest release of the SDK, please update your composer dependencies.

#### Call to undefined function `openssl\_sign()`[¶](#call-to-undefined-function-openssl-sign "Permalink to this headline")

You need to install the OpenSSL PHP Extension: <http://php.net/openssl>

#### Default sound not played on message delivery[¶](#default-sound-not-played-on-message-delivery "Permalink to this headline")

If you specified `'sound' => 'default'` in the message payload, try chaning it

to `'sound' => "default"` - although single or double quotes shouldn’t™ make

a difference, [it has been reported that this can solve the issue](https://github.com/kreait/firebase-php/issues/454#issuecomment-706771776).

#### cURL error XX: …[¶](#curl-error-xx "Permalink to this headline")

If you receive a `cURL error XX: ...`, make sure that you have a current

CA Root Certificates bundle on your system and that PHP uses it.

To see where PHP looks for the CA bundle, check the output of the

following command:

```

var\_dump(openssl\_get\_cert\_locations());

```

which should lead to an output similar to this:

```

array(8) {

    'default\_cert\_file' =>

    string(32) "/usr/local/etc/openssl/cert.pem"

    'default\_cert\_file\_env' =>

    string(13) "SSL\_CERT\_FILE"

    'default\_cert\_dir' =>

    string(29) "/usr/local/etc/openssl/certs"

    'default\_cert\_dir\_env' =>

    string(12) "SSL\_CERT\_DIR"

    'default\_private\_dir' =>

    string(31) "/usr/local/etc/openssl/private"

    'default\_default\_cert\_area' =>

    string(23) "/usr/local/etc/openssl"

    'ini\_cafile' =>

    string(0) ""

    'ini\_capath' =>

    string(0) ""

}

```

Now check if the file given in the `default\_cert\_file` field actually exists.

Create a backup of the file, download the current CA bundle from

<https://curl.haxx.se/ca/cacert.pem> and put it where `default\_cert\_file`

points to.

If the problem still occurs, another possible solution is to configure the `curl.cainfo`

setting in your `php.ini`:

```

[curl]

curl.cainfo = /absolute/path/to/cacert.pem

```

#### “403 Forbidden” Errors[¶](#forbidden-errors "Permalink to this headline")

Under the hood, a Firebase project is actually a Google Cloud project with pre-defined and pre-allocated

permissions and resources.

When Google adds features to its product line, it is possible that you have to manually configure your

Firebase/Google Cloud Project to take advantage of those new features.

When a request to the Firebase APIs fails, please make sure that the according Google Cloud API is

enabled for your project:

* Firebase Services: <https://console.cloud.google.com/apis/library/firebase.googleapis.com>

* Cloud Messaging (FCM): <https://console.cloud.google.com/apis/library/fcm.googleapis.com>

* FCM Registration API: <https://console.cloud.google.com/apis/library/fcmregistrations.googleapis.com>

* Dynamic Links: <https://console.cloud.google.com/apis/library/firebasedynamiclinks.googleapis.com>

* Firestore: <https://console.cloud.google.com/apis/library/firestore.googleapis.com>

* Realtime Database Rules: <https://console.cloud.google.com/apis/library/firebaserules.googleapis.com>

* Remote Config: <https://console.cloud.google.com/apis/library/firebaseremoteconfig.googleapis.com>

* Storage: <https://console.cloud.google.com/apis/library/storage-component.googleapis.com>

Please also make sure that the Service Account you are using for your project has all necessary

roles and permissions as described in the official documentation at [Manage project access with Firebase IAM](https://firebase.google.com/docs/projects/iam/overview).

#### MultiCast SendReports are empty[¶](#multicast-sendreports-are-empty "Permalink to this headline")

This is an issue seen in XAMPP/WAMP environments and seems related to the cURL version shipped with

the current PHP installation. Please ensure that cURL is installed with at least version **7.67**

(preferably newer, version 7.70 is known to work).

You can check the currently installed cURL version by adding the following line somewhere in your

code:

```

echo curl\_version()['version']; exit;

```

To install a newer version of cURL, download the latest release from <https://curl.haxx.se/> . From

the unpacked archive in the `bin` folder, use the file ending with `libcurl\*.dll` to overwrite

the existing `libcurl\*.dll` in the `ext` folder of your PHP installation and restart the

environment.

If this issue occurs in other environments (e.g. Linux or MacOS), please ensure that you have the

latest (minor) versions of PHP and cURL installed. If the problem persists, please open an issue

in the issue tracker.

#### Proxy configuration[¶](#proxy-configuration "Permalink to this headline")

If you need to access the Firebase/Google APIs through a proxy, you can specify an according

HTTP Client option while configuring the service factory: [HTTP Client Options](index.html#http-client-options)

#### Debugging[¶](#debugging "Permalink to this headline")

In order to debug HTTP requests to the Firebase/Google APIs, you can enable the factory’s

debug mode and provide an instance of `Psr\Log\LoggerInterface`. HTTP requests and

responses will then be pushed to this logger with their full headers and bodies.

```

$factory = $factory->withHttpDebugLogger($logger);

```

If you want to make sure that the Factory has the configuration you expect it to have,

call the `getDebugInfo()` method:

```

$factoryInfo = $factory->getDebugInfo();

```

The output will be something like this:

The private key of a service account will be redacted.

