Getting Started on Heroku Fir with PHP
Introduction
Complete this tutorial to deploy a sample PHP app to Heroku Private Spaces on the Fir generation of the platform. To deploy the app to the Common Runtime or Cedar Private Spaces, follow this guide instead.
The tutorial assumes that you have:
- A verified Heroku Account;
- An existing Fir Private Space;
- A team admin or member role that has the
app creation
permission on the space; - An SSH key added to your Heroku account;
- PHP version 8 installed locally - see the Installation and Configuration section of the PHP Manual;
- Composer installed locally - see the Getting Started section of the Composer documentation.
Using dynos and databases to complete this tutorial counts towards your usage. We recommend using 1X-Classic dynos and an Essential-0 Postgres database to complete this tutorial. Delete all resources after completing the tutorial.
Set Up
The Heroku CLI requires Git, the popular version control system. If you don’t already have Git installed, complete the following before proceeding:
Install the Heroku Command Line Interface (CLI). Use the CLI to manage and scale your app, provision add-ons, view your logs, and run your app locally.
Download and run the installer for your platform:
$ brew tap heroku/brew && brew install heroku
Download the appropriate installer for your Windows installation:
You can find more installation options for the Heroku CLI here.
After installation, you can use the heroku
command from your command shell.
To log in to the Heroku CLI, use the heroku login
command:
$ heroku login
heroku: Press any key to open up the browser to login or q to exit:
Opening browser to https://cli-auth.heroku.com/auth/cli/browser/***
heroku: Waiting for login...
Logging in... done
Logged in as me@example.com
This command opens your web browser to the Heroku login page. If your browser is already logged in to Heroku, click the Log In
button on the page.
This authentication is required for the heroku
and git
commands to work correctly.
If you have any problems installing or using the Heroku CLI, see the main Heroku CLI article for advice and troubleshooting steps.
If you’re behind a firewall that uses a proxy to connect with external HTTP/HTTPS services, set the HTTP_PROXY
or HTTPS_PROXY
environment variables in your local development environment before running the heroku
command.
Clone the Sample App
If you’re new to Heroku, it’s recommended that you complete this tutorial using the Heroku-provided sample application.
To deploy an existing application, follow the Preparing a Codebase for Heroku Deployment article instead.
Clone the sample application to get a local version of the code. Execute these commands in your local command shell or terminal:
$ git clone https://github.com/heroku/php-getting-started.git
$ cd php-getting-started
You now have a functioning Git repository with a simple PHP app that uses the Slim micro framework. It includes a composer.json
file that specifies the necessary dependencies, as well as a version range for the PHP language runtime.
Define a Procfile
Use a Procfile, a text file in the root directory of your application, to explicitly declare what command to execute to start your app.
The Procfile
in the example app looks like this:
web: heroku-php-apache2 web/
This Procfile declares a single process type, web
, and the command needed to run it. The name web
is important here. It declares that this process type is attached to Heroku’s HTTP routing stack and receives web traffic when deployed. The command used here starts PHP’s FPM server together with Apache HTTPD, the web server, and instructs it to serve the app from the web/
directory of the codebase.
A Procfile can contain additional process types. For example, you can declare a background worker process that processes items off a queue.
IPv6 Compatibility
Fir uses IPv6 to route web requests. When using Apache HTTPD or Nginx for an app on Heroku (using the heroku-php-apache2
or heroku-php-nginx
commands in Procfile
), they will automatically bind to the correct interface and port on startup.
Sometimes, you may wish to use PHP’s built-in web server during early development of your app. In that case, it is important to have the server listen on IPv6 interfaces in order to allow traffic to reach the dyno.
Instead of using the IPv4 address “0.0.0.0
” to listen on all IPv4 interfaces, the IPv6 shorthand address “::
” is used. Because colons (“:
”) are also used to separate addresses and ports, IPv6 addresses are wrapped in square brackets, for example “[::]
”. Many command shells treat square brackets as special characters, so such an address must be wrapped in quotation marks. Since the port number a Heroku app must bind to is available in the PORT
environment variable, double quotation marks are used to allow the variable to expand.
Putting all of these instructions together, a possible Procfile
that serves our getting started app using PHP’s built-in web server from the web/
subdirectory of the app could look like this:
web: php -S "[::]:${PORT}" -t "web/"
In most cases, however, you will not need to use this approach, as Apache HTTPD or Nginx are the recommended web servers for production applications.
Create Your App in a Fir Space
Delete your app and database as soon as you’re done to control costs.
You can get a list of all Heroku spaces by running $ heroku spaces
Create an app on Heroku to prepare the platform to receive your source code by replacing <space-name>
with the name of your Fir space in the command below:
$ heroku create --space <space-name>
Creating app in space <space name>...
Creating app in space <space name>... done, infinite-springs-62063
http://infinite-springs-62063-0ba126a743db.herokuapp.com/ | https://git.heroku.com/infinite-springs-62063.git
When you create an app, a Git remote called heroku
also gets created and associated with your local Git repository. Git remotes are versions of your repository that live on other servers. You deploy your app by pushing its code to that special Heroku-hosted remote associated with your app.
Heroku generates a random name for your app, in this case, infinite-springs-62063
. You can specify your own app name.
Deploy the App
Using a dyno to complete this tutorial counts towards your usage. Delete your app and database as soon as you’re done to control costs.
Deploy your code. This command pushes the main
branch of the sample repo to your heroku
remote, which then deploys to Heroku:
$ git push heroku main
remote: Updated 17 paths from a3f5634
remote: Compressing source files... done.
remote: Building source:
remote: Extracting source
remote: Image with name "infinite-springs-62063/builds" not found
remote: 2 of 3 buildpacks participating
remote: heroku/php 0.2.0
remote: heroku/procfile 3.1.2
remote:
remote: [Bootstrapping]
remote:
remote: [Preparing platform packages installation]
remote:
remote: [Installing platform packages]
remote: No composer.lock file present. Updating dependencies to latest instead of installing from lock file. See https://getcomposer.org/install for more information.
remote: Loading composer repositories with package information
remote: Updating dependencies
remote: Lock file operations: 26 installs, 0 updates, 0 removals
remote: - Locking fig/http-message-util (1.1.5)
remote: - Locking heroku-sys/composer (2.8.2)
remote: - Locking heroku-sys/php (8.3.13)
remote: - Locking heroku/installer-plugin (1.8.0)
remote: - Locking laravel/serializable-closure (v1.3.7)
remote: - Locking monolog/monolog (3.8.0)
remote: - Locking nikic/fast-route (v1.3.0)
remote: - Locking php-di/invoker (2.3.4)
remote: - Locking php-di/php-di (7.0.7)
remote: - Locking php-di/slim-bridge (3.4.1)
remote: - Locking psr/container (2.0.2)
remote: - Locking psr/http-factory (1.1.0)
remote: - Locking psr/http-message (2.0)
remote: - Locking psr/http-server-handler (1.0.2)
remote: - Locking psr/http-server-middleware (1.0.2)
remote: - Locking psr/log (3.0.2)
remote: - Locking ralouphie/getallheaders (3.0.3)
remote: - Locking slim/psr7 (1.7.0)
remote: - Locking slim/slim (4.14.0)
remote: - Locking slim/twig-view (3.4.1)
remote: - Locking symfony/deprecation-contracts (v3.5.1)
remote: - Locking symfony/polyfill-ctype (v1.31.0)
remote: - Locking symfony/polyfill-mbstring (v1.31.0)
remote: - Locking symfony/polyfill-php80 (v1.31.0)
remote: - Locking symfony/polyfill-php81 (v1.31.0)
remote: - Locking twig/twig (v3.16.0)
remote: Writing lock file
remote: Installing dependencies from lock file
remote: Package operations: 26 installs, 0 updates, 0 removals
remote: - Installing heroku/installer-plugin (1.8.0): Mirroring from /layers/heroku_php/bootstrap_installer/support/installer
remote: - Downloading heroku-sys/php (8.3.13)
remote: - Downloading heroku-sys/composer (2.8.2)
remote: 0/2 [>---------------------------] 0%
remote: 1/2 [==============>-------------] 50%
remote: 2/2 [============================] 100%
remote: - Installing heroku-sys/php (8.3.13)
remote: - Installing fig/http-message-util (1.1.5)
remote: - Installing heroku-sys/composer (2.8.2)
remote: - Installing laravel/serializable-closure (v1.3.7)
remote: - Installing monolog/monolog (3.8.0)
remote: - Installing nikic/fast-route (v1.3.0)
remote: - Installing php-di/invoker (2.3.4)
remote: - Installing php-di/php-di (7.0.7)
remote: - Installing php-di/slim-bridge (3.4.1)
remote: - Installing psr/container (2.0.2)
remote: - Installing psr/http-factory (1.1.0)
remote: - Installing psr/http-message (2.0)
remote: - Installing psr/http-server-handler (1.0.2)
remote: - Installing psr/http-server-middleware (1.0.2)
remote: - Installing psr/log (3.0.2)
remote: - Installing ralouphie/getallheaders (3.0.3)
remote: - Installing slim/psr7 (1.7.0)
remote: - Installing slim/slim (4.14.0)
remote: - Installing slim/twig-view (3.4.1)
remote: - Installing symfony/deprecation-contracts (v3.5.1)
remote: - Installing symfony/polyfill-ctype (v1.31.0)
remote: - Installing symfony/polyfill-mbstring (v1.31.0)
remote: - Installing symfony/polyfill-php80 (v1.31.0)
remote: - Installing symfony/polyfill-php81 (v1.31.0)
remote: - Installing twig/twig (v3.16.0)
remote: 0 [>---------------------------] 0 [->--------------------------]
remote: Generating autoload files
remote:
remote: [Installing web servers]
remote: No composer.lock file present. Updating dependencies to latest instead of installing from lock file. See https://getcomposer.org/install for more information.
remote: Loading composer repositories with package information
remote: Updating dependencies
remote: Lock file operations: 4 installs, 0 updates, 0 removals
remote: - Locking heroku-sys/apache (2.4.62)
remote: - Locking heroku-sys/nginx (1.26.2)
remote: - Locking heroku/heroku-buildpack-php (dev-bundled)
remote: - Locking heroku/installer-plugin (1.8.0)
remote: Writing lock file
remote: Installing dependencies from lock file
remote: Package operations: 4 installs, 0 updates, 0 removals
remote: - Installing heroku/installer-plugin (1.8.0): Mirroring from /layers/heroku_php/bootstrap_installer/support/installer
remote: - Downloading heroku-sys/apache (2.4.62)
remote: - Downloading heroku-sys/nginx (1.26.2)
remote: 0/2 [>---------------------------] 0%
remote: 2/2 [============================] 100%
remote: - Installing heroku-sys/apache (2.4.62)
remote: - Installing heroku-sys/nginx (1.26.2)
remote: - Installing heroku/heroku-buildpack-php (dev-bundled): Mirroring from /layers/heroku_php/bootstrap_installer
remote: 0 [>---------------------------] 0 [->--------------------------]
remote: Generating autoload files
remote:
remote: [Installing dependencies]
remote: Installing dependencies from lock file
remote: Verifying lock file contents can be installed on current platform.
remote: Dependency resolution completed in 0.000 seconds
remote: Package operations: 23 installs, 0 updates, 0 removals
remote: Installs: laravel/serializable-closure:v1.3.7, psr/log:3.0.2, monolog/monolog:3.8.0, nikic/fast-route:v1.3.0, psr/http-message:2.0, psr/http-server-handler:1.0.2, psr/http-server-middleware:1.0.2, psr/http-factory:1.1.0, psr/container:2.0.2, slim/slim:4.14.0, php-di/invoker:2.3.4, php-di/php-di:7.0.7, php-di/slim-bridge:3.4.1, symfony/polyfill-php80:v1.31.0, ralouphie/getallheaders:3.0.3, fig/http-message-util:1.1.5, slim/psr7:1.7.0, symfony/polyfill-php81:v1.31.0, symfony/polyfill-mbstring:v1.31.0, symfony/polyfill-ctype:v1.31.0, symfony/deprecation-contracts:v3.5.1, twig/twig:v3.16.0, slim/twig-view:3.4.1
remote: - Downloading laravel/serializable-closure (v1.3.7)
remote: - Downloading psr/log (3.0.2)
remote: - Downloading monolog/monolog (3.8.0)
remote: - Downloading nikic/fast-route (v1.3.0)
remote: - Downloading psr/http-message (2.0)
remote: - Downloading psr/http-server-handler (1.0.2)
remote: - Downloading psr/http-server-middleware (1.0.2)
remote: - Downloading psr/http-factory (1.1.0)
remote: - Downloading psr/container (2.0.2)
remote: - Downloading slim/slim (4.14.0)
remote: - Downloading php-di/invoker (2.3.4)
remote: - Downloading php-di/php-di (7.0.7)
remote: - Downloading php-di/slim-bridge (3.4.1)
remote: - Downloading symfony/polyfill-php80 (v1.31.0)
remote: - Downloading ralouphie/getallheaders (3.0.3)
remote: - Downloading fig/http-message-util (1.1.5)
remote: - Downloading slim/psr7 (1.7.0)
remote: - Downloading symfony/polyfill-php81 (v1.31.0)
remote: - Downloading symfony/polyfill-mbstring (v1.31.0)
remote: - Downloading symfony/polyfill-ctype (v1.31.0)
remote: - Downloading symfony/deprecation-contracts (v3.5.1)
remote: - Downloading twig/twig (v3.16.0)
remote: - Downloading slim/twig-view (3.4.1)
remote: - Installing laravel/serializable-closure (v1.3.7): Extracting archive
remote: - Installing psr/log (3.0.2): Extracting archive
remote: - Installing monolog/monolog (3.8.0): Extracting archive
remote: - Installing nikic/fast-route (v1.3.0): Extracting archive
remote: - Installing psr/http-message (2.0): Extracting archive
remote: - Installing psr/http-server-handler (1.0.2): Extracting archive
remote: - Installing psr/http-server-middleware (1.0.2): Extracting archive
remote: - Installing psr/http-factory (1.1.0): Extracting archive
remote: - Installing psr/container (2.0.2): Extracting archive
remote: - Installing slim/slim (4.14.0): Extracting archive
remote: - Installing php-di/invoker (2.3.4): Extracting archive
remote: - Installing php-di/php-di (7.0.7): Extracting archive
remote: - Installing php-di/slim-bridge (3.4.1): Extracting archive
remote: - Installing symfony/polyfill-php80 (v1.31.0): Extracting archive
remote: - Installing ralouphie/getallheaders (3.0.3): Extracting archive
remote: - Installing fig/http-message-util (1.1.5): Extracting archive
remote: - Installing slim/psr7 (1.7.0): Extracting archive
remote: - Installing symfony/polyfill-php81 (v1.31.0): Extracting archive
remote: - Installing symfony/polyfill-mbstring (v1.31.0): Extracting archive
remote: - Installing symfony/polyfill-ctype (v1.31.0): Extracting archive
remote: - Installing symfony/deprecation-contracts (v3.5.1): Extracting archive
remote: - Installing twig/twig (v3.16.0): Extracting archive
remote: - Installing slim/twig-view (3.4.1): Extracting archive
remote: Generating optimized autoload files
remote: 10 packages you are using are looking for funding.
remote: Use the `composer fund` command to find out more!
remote:
remote: [Preparing Composer runtime environment]
remote:
remote: [Discovering process types]
remote: Procfile declares types -> web
remote: Adding layer 'heroku/php:composer_env'
remote: Adding layer 'heroku/php:platform'
remote: Adding layer 'heroku/php:webservers'
remote: Adding layer 'buildpacksio/lifecycle:launch.sbom'
remote: Added 1/1 app layer(s)
remote: Adding layer 'buildpacksio/lifecycle:launcher'
remote: Adding layer 'buildpacksio/lifecycle:config'
remote: Adding layer 'buildpacksio/lifecycle:process-types'
remote: Adding label 'io.buildpacks.lifecycle.metadata'
remote: Adding label 'io.buildpacks.build.metadata'
remote: Adding label 'io.buildpacks.project.metadata'
remote: Setting default process type 'web'
remote: Saving infinite-springs-62063/builds...
remote: *** Images (sha256:80061b72beca63ddc7ec94d764569c2a3924c7f357e1d70a8d996c01e682ecd3):
remote: infinite-springs-62063/builds:f6de4260-88d4-49b4-9c38-3d078f102164
remote: Adding cache layer 'heroku/php:composer_cache'
remote: Adding cache layer 'heroku/php:platform_cache'
remote: Uploading cache
remote: Launching...
remote: http://infinite-springs-62063-0ba126a743db.herokuapp.com/ deployed to Heroku
remote: Verifying deploy... done.
To https://git.heroku.com/infinite-springs-62063.git
* [new branch] main -> main
The app is now deployed. The default dyno size for Fir Private Spaces is 1X-Classic.
Visit the app at the URL shown in the logs. As a shortcut, you can also open the website as follows:
$ heroku open
View Logs
Fir apps do not retain log history like Cedar apps. To view an event in your Fir logs, you must run the logging command while that event occurs.
Heroku treats logs as streams of time-ordered events, aggregated from the output streams of all your app and Heroku components. Heroku provides a single stream for all events. View information about your running app by using one of the logging commands:
$ heroku logs
Fetching logs...
2024-12-16T20:17:12.072129+00:00 app[web-77f9f8f475-tx4mx]: [2024-12-16T20:17:11.891691+00:00] default.DEBUG: logging output. [] []
2024-12-16T20:17:12.072188+00:00 app[web-77f9f8f475-tx4mx]: 2600:1f18:5cec:4a05:40b::18 - - [16/Dec/2024:20:17:11 +0000] "GET / HTTP/1.1" 200 8798 "-" "curl/8.7.1
2024-12-16T20:17:15.558524+00:00 heroku-router[web]: at=info method=GET path="/" host=infinite-springs-62063-0ba126a743db.herokuapp.com request_id=190dbba4-08d2-79ae-7318-1221c96a6cbd fwd="13.110.54.15" dyno=web-77f9f8f475-tx4mx connect=1ms service=7ms status=200 bytes=8798 protocol=http tls_version=tls1.3
To generate more log messages, refresh the app in your browser.
To stop streaming the logs, press Ctrl
+C
.
Install App Dependencies Locally
Heroku recognizes an app as a PHP app by the existence of a composer.json
file in the root directory.
The demo app you deployed already has a composer.json
:
{
"require" : {
"php": "^8.1",
"php-di/php-di": "^7.0",
"slim/slim": "^4.0",
"php-di/slim-bridge": "^3.4.1",
"slim/psr7": "^1.3.0",
...
The composer.json
file specifies the dependencies to install with your application. It also determines the version of PHP used to run your application on Heroku, and which PHP extensions to enable.
Every app that has dependencies listed in composer.json
also requires the corresponding composer.lock
lock file to be present. Any time composer.json
is modified, composer update
must be run to ensure the lock file is up to date. Running composer install
installs the dependencies that were “frozen” to composer.lock
during the last update.
When an app deploys, Heroku installs the appropriate PHP and extension packages, as well as regular dependencies, listed in the lock file.
Run composer install
in your local directory to install the dependencies, preparing your system for running the app locally:
$ composer install
Installing dependencies from lock file (including require-dev)
Verifying lock file contents can be installed on current platform.
Package operations: 24 installs, 0 updates, 0 removals
0 [>---------------------------] 0 [->--------------------------]
- Installing heroku/heroku-buildpack-php (v259): Extracting archive
- Installing laravel/serializable-closure (v1.3.7): Extracting archive
- Installing psr/log (3.0.2): Extracting archive
- Installing monolog/monolog (3.8.0): Extracting archive
After installing dependencies, you can run your app locally.
Push Local Changes
In this step, you propagate a local change to the application to Heroku.
First, we modify composer.json
to include an additional dependency for the alkri11es/cowsayphp
library:
$ composer require alrik11es/cowsayphp
./composer.json has been updated
Running composer update alrik11es/cowsayphp
Loading composer repositories with package information
Updating dependencies
Lock file operations: 1 install, 0 updates, 0 removals
- Locking alrik11es/cowsayphp (1.2.0)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 1 install, 0 updates, 0 removals
- Installing alrik11es/cowsayphp (1.2.0): Extracting archive
Generating autoload files
10 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
No security vulnerability advisories found.
Using version ^1.2 for alrik11es/cowsayphp
This will modify the “require
” section of composer.json
for you, and update the composer.lock
lock file to reflect the newly installed dependency.
If you introduced the dependency by changing the composer.json
file yourself, be sure to update the dependencies by running composer update
instead.
The library is now ready for use. Since our example app uses PHP-DI for Dependency Injection, you must first add another entry to the container near the top of the file, so that PHP-DI knows how to instantiate an animal class instance from the Cowsayphp\Farm
namespace when a Cowsayphp\AnimalInterface
is used.
In file web/index.php
, on line 28 add:
// Add Cowsay to Container
$container->set(\Cowsayphp\AnimalInterface::class, function() {
return \Cowsayphp\Farm::create(\Cowsayphp\Farm\Cow::class);
});
When definining a new route near the bottom of web/index.php
, its function’s AnimalInterface
type hint will cause PHP-DI to automatically inject a Cow
farm animal instance.
In file web/index.php
, on line 42 add:
$app->get('/coolbeans', function(Request $request, Response $response, LoggerInterface $logger, \Cowsayphp\AnimalInterface $animal) {
$logger->debug('letting the Cowsay library write something cool.');
$response->getBody()->write("<pre>".$animal->say("Cool beans")."</pre>");
return $response;
});
Now deploy this local change to Heroku.
Almost every deploy to Heroku follows this same pattern. First, add the modified files to the local Git repository:
$ git add composer.json composer.lock web/index.php
Then commit the changes to the repository:
$ git commit -m "Added cowsay library and endpoint"
[main d6689d3] Added cowsay library and endpoint
3 files changed, 70 insertions(+), 2 deletions(-)
Next, deploy just as before:
$ git push heroku main
Finally, check that everything is working:
$ heroku open
Debugging
The Heroku PHP Cloud Native Buildpack turns your code into an Open Container Initiative (OCI) container image when you deploy to Fir. This image gets executed on our dynos.
You can use this image locally to reproduce and debug deployment problems. Build an OCI image from your application to debug locally by using the Heroku PHP Cloud Native Buildpack. If you’re interested, check out the buildpack docs.
Start a Console
The heroku run
command to launch an interactive one-off dyno is unavailable for Fir. As an alternative, use heroku run:inside
to access a running dyno until we add heroku run
for Fir.
You must add an SSH key to your Heroku account before running this command.
To execute the command you need the name of a currently running process. You can see a list with heroku ps
:
$ heroku ps
=== web (1X-Classic): heroku-php-apache2 web/ (1)
web-77f9f8f475-tx4mx: up 2024/12/16 14:17:11 -0600 (~ 8s ago)
Use that dyno name to run a command like php -v
:
$ heroku run:inside web-77f9f8f475-tx4mx "php -v"
Running launcher php -v on infinite-springs-62063...
Running launcher php -v on infinite-springs-62063... up, web-77f9f8f475-tx4mx
PHP 8.3.13 (cli) (built: Nov 1 2024 11:24:33) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.3.13, Copyright (c) Zend Technologies
with Zend OPcache v8.3.13, Copyright (c), by Zend Technologies
If you receive an error, Error connecting to process
, configure your firewall.
Let’s try another example. Create another one-off process within your running dyno and run the bash
command to open up a shell on that dyno.
You can use this to view the contents of the dyno’s disk:
$ heroku run:inside web-77f9f8f475-tx4mx "bash"
Running launcher bash on infinite-springs-62063...
Running launcher bash on infinite-springs-62063... up, web-77f9f8f475-tx4mx
heroku@web-77f9f8f475-tx4mx:/workspace$ ls -lah
total 80K
drwxrwsrwx. 6 heroku heroku 168 Jan 1 1980 .
drwxr-xr-x. 1 root root 54 Dec 16 20:17 ..
drwxr-xr-x. 2 heroku heroku 46 Jan 1 1980 .github
-rw-r--r--. 1 heroku heroku 13 Jan 1 1980 .gitignore
-rw-r--r--. 1 heroku heroku 29 Jan 1 1980 Procfile
-rw-r--r--. 1 heroku heroku 2.5K Jan 1 1980 README.md
-rw-r--r--. 1 heroku heroku 199 Jan 1 1980 app.json
-rw-r--r--. 1 heroku heroku 308 Jan 1 1980 composer.json
-rw-r--r--. 1 heroku heroku 57K Jan 1 1980 composer.lock
drwxr-sr-x. 13 heroku heroku 177 Jan 1 1980 vendor
drwxr-xr-x. 2 heroku heroku 78 Jan 1 1980 views
drwxr-xr-x. 4 heroku heroku 73 Jan 1 1980 web
heroku@web-77f9f8f475-tx4mx:/workspace$ exit
exit
Type exit
to exit the shell and terminate the dyno.
Define Config Vars
Heroku lets you externalize configuration by storing data such as encryption keys or external resource addresses in config vars.
At runtime, we expose config vars as environment variables to the application, which you can read using PHP’s getenv function. This way, your app source does not contain hard-coded credentials for databases, external API endpoints and so forth.
In addition to storing credentials such as database connection information, it’s also common practice to place configuration flags or values that control essential behavior of your app into config vars.
For example, the Cowsay library supports other types of animals, and this example will use an environment variable named COWSAY_FARM_CLASS
to control which class is used. In web/index.php
, locate the section you added earlier, and modify it so that the DI container uses the value of the environment variable to construct the class name dynamically:
// Add Cowsay to Container
$container->set(\Cowsayphp\AnimalInterface::class, function() {
$class = '\\Cowsayphp\\Farm\\'.(getenv("COWSAY_FARM_CLASS")?:'Cow');
return \Cowsayphp\Farm::create($class);
});
If the environment variable is not set, it will default to returning a Cow
instance, but if you now set the COWSAY_FARM_CLASS
config var on your app to another value, it will be used instead:
$ heroku config:set COWSAY_FARM_CLASS=Dragon
Setting COWSAY_FARM_CLASS and restarting infinite-springs-62063...
Setting COWSAY_FARM_CLASS and restarting infinite-springs-62063... done, v4
COWSAY_FARM_CLASS: Dragon
To see this change in action, deploy your changed application to Heroku once again, using the same git add web/index.php
, git commit
, and git push
sequence of commands you used earlier.
Delete Your App
Remove the app from your account. We only charge you for the resources you used.
This action permanently deletes your application and any add-ons attached to it.
$ heroku apps:destroy
You can confirm that your app is gone with this command:
$ heroku apps --all
Next Steps
You now know how to configure and deploy a PHP app, view logs, and start a console.
To learn more, see:
Here’s some recommended reading:
- How Heroku Works is a technical overview of the concepts you encounter while writing, configuring, deploying, and running applications.
- Preparing a Codebase for Heroku Deployment contains general deployment recommendations, while Deploying PHP Apps on Heroku offers more PHP-specific guidance.
- The PHP support category contains many resources for managing and deploying PHP apps on Heroku.
- Framework-specific articles contain useful pointers for deploying Laravel and Symfony apps.