Heroku PHP Support

Last Updated: 19 February 2015

apache extension hhvm nginx php

Table of Contents

This document describes the general behavior of the Heroku Cedar stack as it relates to the recognition and execution of PHP applications.

Activation

The Heroku PHP Support will be applied to applications only when the application has a file named composer.json in the root directory. Even if an application has no Composer dependencies, it must include an empty composer.json in order to be recognized as a PHP application.

When Heroku recognizes a PHP application, it will respond accordingly during a push:

$ git push heroku master
-----> PHP app detected

PHP runtimes

Heroku makes a number of different runtimes available. You can use HHVM, PHP, or both simultaneously.

Supported runtimes

Heroku’s PHP support extend to apps using PHP 5.5 (5.5.22, 64-bit) and PHP 5.6 (5.6.6, 64-bit), which is also the default PHP runtime for apps.

The PHP runtimes have OPcache enabled for improved performance, with a configuration optimized for the specific characteristics of Heroku’s dynos.

Alternative runtimes

Heroku currently allows installation of the following experimental, unsupported runtimes:

  • HHVM (3.3.3, 64-bit)
  • HHVM (3.5.1, 64-bit)

These runtimes are available on the cedar-14 stack only and can be enabled via composer.json.

Default runtime

If no runtime is specified, the default will be the latest stable PHP version. Heroku will display this information upon a push:

-----> No runtime requirements in composer.json, defaulting to PHP 5.6.6.

Selecting a runtime

You may select the runtime(s) to use via Composer Platform Packages in composer.json. Upon a push, Heroku will read the necessary information from composer.lock, if present, and fall back to composer.json otherwise.

For example, the following composer.json will instruct Heroku to use the latest 5.6.x version of PHP:

{
  "require": {
    "php": "~5.6.0"
  }
}

Never specify an exact version like “5.5.16” for PHP or “3.2.0” for HHVM. Instead, use the ~ (“next significant release”) operator to ensure that you get appropriate updates upon push as they become available. For PHP, that means specifying “~5.5.16” will always get you the latest 5.5 release, which will be fully compatible with other releases from the 5.5 series (but may contain security or performance updates), but not 5.6.0 or later. For HHVM, due to the different versioning and backwards compatibility policies that are currently in effect, it is recommended to specify “~3.3” instead to receive the latest “3.x.0” versions available.

Heroku will print the versions that were resolved and will be installed:

-----> Resolved composer.lock requirement for PHP >=5.3.3 to version 5.6.6.
-----> Resolved composer.lock requirement for HHVM 3.* to version 3.5.1.

Specifying an unknown or unsupported version will result in an error.

You may select both HHVM and PHP as runtimes. Both will be available, and depending on what boot script you use, one of them will be used to handle requests from the web server.

PHP

Specify “php” as a dependency in the require section of your composer.json to use PHP as the runtime:

{
  "require": {
    "php": "~5.5.12"
  }
}

Always prefix the minimum version you’d like to receive with the ~ selector. This ensures that you’ll receive updated versions as they become available. In the example above, you’d get PHP 5.5.12 or later, but not 5.6.0 (which you may want to test your application against first in case of any unexpected backwards compatibility issues).

Next, ensure that your new requirements are “frozen” to composer.lock by running:

$ composer update

Finally, don’t forget to add and commit both files. A composer.lock may not be generated if your composer.json doesn’t list any user-land packages (e.g. monolog/monolog) as dependencies.

HHVM

Support for HHVM is highly experimental. Functionality may change prior to general availability.

Specify “hhvm” as a dependency in the require section of your composer.json to use HHVM as the runtime:

{
  "require": {
    "hhvm": "~3.3"
  }
}

Always prefix the minimum version you’d like to receive with the ~ selector. This ensures that you’ll receive updated versions as they become available. In the example above, you’d get HHVM 3.3 or later, but not 4.0 (which you may want to test your application against first in case of any unexpected backwards compatibility issues).

Next, ensure that your new requirements are “frozen” to composer.lock by running:

$ composer update

Finally, don’t forget to add and commit both files. A composer.lock may not be generated if your composer.json doesn’t list any user-land packages (e.g. monolog/monolog) as dependencies.

If you specify hhvm as a dependency in your project, Composer will check for it during composer update or composer install commands.

This means that you need HHVM installed on the computer where you run the command, and you need to run Composer using HHVM (e.g. by running hhvm $(which composer) update or hhvm composer.phar update) for Composer to successfully finish the operation and write a composer.lock lock file.

If you cannot install HHVM on your computer (something we recommend in the interest of maintaining dev/prod parity), you can instruct composer to ignore the missing (so-called “platform”) requirement:

$ composer update --ignore-platform-reqs

The same --ignore-platform-reqs flag may also be used when running composer install on subsequent dependency installations in new environments, e.g. on other developers' computers, where HHVM is similarly unavailable.

Supported versions

PHP

  • 5.5.22
  • 5.6.6 (default)

HHVM

Upgrades

If you deploy an application that does not declare a runtime version dependency, the then-latest version of PHP will be used. Your application will be upgraded to more recent versions of PHP 5 if available automatically upon the next deploy.

If your application declares runtime version dependencies, the most recent version matching the version constraint will be selected for installation.

Extensions

PHP 5.5 and 5.6

The following built-in extensions are enabled automatically on Heroku (this list does not include extensions that PHP enables by default, such as DOM, JSON, PCRE or PDO):

The following built-in extensions have been built “shared” and can be enabled through composer.json (internal identifier names given in parentheses):

The following third-party extensions can be enabled through composer.json (internal identifier names given in parentheses):

HHVM

HHVM is built with its standard set of extensions. Custom extensions for HHVM are not currently supported.

Using optional extensions

You may declare any optional extensions you want to use via composer.json using Composer Platform Packages; simply prefix any of the identifiers in the list of extensions above with “ext-” in the package name.

For example, to enable extensions for using bcmath, Memcached, MongoDB and XSL:

{
    "require": {
        "ext-bcmath": "*",
        "ext-memcached": "*",
        "ext-mongo": "*",
        "ext-xsl": "*"
    }
}

It is strongly recommended that you use “*” as the version selector when specifying extensions, as their version numbers can be extremely inconsistent (most of them report their version as “0”) and Heroku will sometimes update extensions outside the regular PHP update cycles.

Next, ensure that your new requirements are “frozen” to composer.lock by running:

$ composer update

Finally, don’t forget to add and commit both files. A composer.lock may not be generated if your composer.json doesn’t list any user-land packages (e.g. monolog/monolog) as dependencies.

If you do not have the desired extension available locally on your computer, the composer update step would fail because the requirements in composer.json cannot be satisfied. If you cannot install the missing extension on your computer using pecl, brew, or similar methods (something you absolutely should do in the interest of maintaining dev/prod parity), you can instruct composer to ignore the missing (so-called “platform”) requirements:

$ composer update --ignore-platform-reqs

The same --ignore-platform-reqs flag may also be used when running composer install on subsequent dependency installations in new environments, e.g. on other developers' computers, where the extension is similarly unavailable.

Upon the next push, Heroku will enable the corresponding PHP extensions:

-----> PHP app detected
-----> Setting up runtime environment...
       - PHP 5.6.6
       - Apache 2.4.10
       - Nginx 1.6.0
-----> Installing PHP extensions:
       - opcache (automatic; bundled, using 'ext-opcache.ini')
       - mongo (composer.json; downloaded, using 'ext-mongo.ini')
       - xsl (composer.json; bundled)
       - bcmath (composer.json; bundled)
       - memcached (composer.json; downloaded, using 'ext-memcached.ini')

Any PHP extension required by a dependency of a project pushed to Heroku will be installed automatically, as the list of extensions to be installed is read from composer.lock.

For example, if a project depends on the stripe/stripe-php PHP SDK for Stripe, the mbstring extension required by the Stripe SDK will automatically be installed upon deploy, without the ext-mbstring package having to be listed explicitly in the require section of your main composer.json.

Customizing settings

PHP

Any .user.ini file that is placed into a project according to the instructions in the PHP manual will be loaded after the main php.ini. You can use these to set any directive permitted in PHP_INI_ALL, PHP_INI_USER and PHP_INI_PERDIR contexts.

For additional details on this and other ways of customizing settings for the PHP runtime, please refer to the corresponding Dev Center article.

HHVM

For details on ways of customizing settings for the HHVM runtime, please refer to the corresponding Dev Center article.

Build behavior

Installation of dependencies

The following command is run during a deploy to resolve dependencies:

$ composer install --no-dev --prefer-dist --optimize-autoloader --no-interaction

The installed version of Composer will be printed for your reference before installation begins.

Composer will always be self-updated to the latest version before this command is run.

Composer’s cache directory is preserved between pushes to speed up package installation.

Custom compile step

For applications that wish to execute an additional compilation step during a build that shouldn’t be part of a standard post-install-cmd Composer script, for example an asset compilation or cache pre-warming procedure, a compile custom command, if present in composer.json, will be executed using the following command:

$ composer compile --no-dev --no-interaction

Any such custom script command defined in composer.json can either be a single string, or an array of commands to execute; example:

{
  "scripts": {
    "compile": [
      "prepare-foo",
      "cleanup-bar"
    ]
  }
}

Composer’s bin-dir is pushed on top of $PATH during command execution, so binaries installed by dependencies are easily accessible as CLI commands when writing scripts without having to use vendor/bin/ or a similar prefix.

Custom Composer versions

If the application contains a composer.phar in the root directory, then that executable will be used instead of the version provided by Heroku.

Running your own version of Composer is not recommended. If you use this feature, you will need to make sure that your version of Composer is up to date. Heroku will not run composer self-update before.

Custom GitHub OAuth tokens

GitHub’s API is subject to rate limits for anonymous requests. If the limit is hit, Composer will fall back to source-based installs instead of distribution tarballs, which will slow down builds.

Using a personal OAuth token raises the limit significantly. To use such a token on Heroku, follow these steps:

  1. Create a new Token (the public_repo and, if you need, repo scopes will suffice)
  2. Copy the token for use in the next command
  3. $ heroku config:set COMPOSER_GITHUB_OAUTH_TOKEN=YOURTOKEN (replacing “YOURTOKEN” with the actual token from the previous step, of course).

Now, pushes to Heroku will use your token during composer install, and Heroku will confirm its usage:

-----> Installing dependencies...
       NOTICE: Using custom GitHub OAuth token in $COMPOSER_GITHUB_OAUTH_TOKEN

For more information, you may also refer to the troubleshooting section in the Composer documentation.

Web servers

Heroku supports Apache 2.4 (2.4.10) and Nginx 1.6 (1.6.0) as dedicated Web servers. For testing purposes, users may of course also use PHP’s built-in Web server, although this is not recommended.

In the absence of a Procfile entry for the “web” dyno type, the Apache Web server will be used together with the PHP or HHVM runtime.

Apache

Apache interfaces with PHP-FPM or HHVM via FastCGI using mod_proxy_fcgi.

To start Apache together with PHP-FPM and all the correct settings, use the heroku-php-apache2 script in the Composer vendor bin dir (usually vendor/bin):

web: vendor/bin/heroku-php-apache2

Vendor binaries are usually installed to vendor/bin by Composer, but under some circumstances (e.g. when running a Symfony2 standard edition project), the location will be different. Run composer config bin-dir to find the right location.

To run HHVM instead, use the heroku-hhvm-apache2 script:

web: vendor/bin/heroku-hhvm-apache2

By default, the root folder of your project will be used as the document root. To use a sub-directory, you may pass the name of a sub-folder as the argument to the boot script, e.g. “public_html”:

web: vendor/bin/heroku-php-apache2 public_html

You can use regular .htaccess files to customize Apache’s behavior, e.g. for URL rewriting. For additional details on this and other options to customize settings for Apache, please refer to the corresponding Dev Center article.

All other

Nginx

Nginx interfaces with PHP-FPM via FastCGI.

To start Nginx together with PHP-FPM and all the correct settings, use the heroku-php-nginx script in the Composer vendor bin dir (usually vendor/bin):

web: vendor/bin/heroku-php-nginx

Vendor binaries are usually installed to vendor/bin by Composer, but under some circumstances (e.g. when running a Symfony2 standard edition project), the location will be different. Run composer config bin-dir to find the right location.

To run HHVM instead, use the heroku-hhvm-nginx script:

web: vendor/bin/heroku-hhvm-nginx

By default, the root folder of your project will be used as the document root. To use a sub-directory, you may pass the name of a sub-folder as the argument to the boot script, e.g. “public_html”:

web: vendor/bin/heroku-php-nginx public_html

For additional details on different ways of customizing settings for Nginx, please refer to the corresponding Dev Center article.

PHP Built-in Web server

For testing purposes, you may start PHP’s built-in Web server by using php -S 0.0.0.0:$PORT as the entry for “web” in your Procfile:

web: php -S 0.0.0.0:$PORT

The Procfile must contain $PORT in the line shown above. It’s used by Heroku at runtime to dynamically bind the web server instance to the correct port for the dyno.

It is important to bind to all interfaces using 0.0.0.0, otherwise Heroku’s routing won’t be able to forward requests to the web server!

You may also pass an alternative document root or use a so called router script to process requests. For details, please refer to the documentation for the built-in Web server.