Running PHP Applications

Running PHP Applications

When running PHP applications, edit the main config file to set the type property to php and select the PHP version to use:

1
2
3
4
5
# .symfony.cloud.yaml

# supported versions: 7.1, 7.2, 7.3
# deprecated versions: 5.4, 5.5, 5.6, 7.0
type: "php:7.3"

PHP code is executed using PHP-FPM and, as of PHP 7.1, SymfonyCloud uses the Zend Thread Safe (ZTS) version of PHP.

PHP Extensions

PHP extensions can be enabled/disabled under the runtime.extensions and runtime.disabled_extensions sections of the main config file:

1
2
3
4
5
6
7
8
# .symfony.cloud.yaml
runtime:
    extensions:
        - http
        - redis
        - ssh2
    disabled_extensions:
        - sqlite3

Default PHP Extensions

The following extensions are enabled by default:

  • bcmath
  • bz2 (not in 7.0)
  • calendar
  • ctype
  • curl
  • date
  • dba
  • dom
  • ereg (5.6 and earlier)
  • exif
  • fileinfo
  • filter
  • ftp
  • gd
  • gettext
  • hash
  • iconv
  • intl
  • json
  • libxml
  • mbstring
  • mcrypt (5.6 and earlier)
  • mhash (5.6 and earlier)
  • mysql (5.6 and earlier)
  • mysqli
  • mysqlnd
  • openssl
  • pcntl
  • pcre
  • pdo
  • pdo_mysql
  • pdo_sqlite
  • phar
  • posix
  • session
  • shmop (5.6 and earlier)
  • simplexml
  • soap
  • sockets
  • sqlite3
  • sysvmsg
  • sysvsem
  • sysvshm
  • tokenizer
  • wddx (5.6 and earlier)
  • xml
  • xmlreader
  • xmlwriter
  • zendopcache (5.4 only) / opcache (5.5 and later)
  • zip
  • zlib

Available PHP Extensions

This is the complete list of extensions supported by SymfonyCloud and the PHP versions where they can be enabled:

Extension 5.4 5.5 5.6 7.0 7.1 7.2 7.3
amqp      
apc
           
apcu
apcu_bc      
applepay      
   
bcmath      
blackfire
bu      
bz2      
calendar      
ctype      
curl
dba      
dom      
enchant
event        
exif      
fileinfo      
ftp      
gd
gearman
       
geoip
gettext      
gmp
http
     
iconv      
igbinary      
imagick
imap
interbase
intl
ioncube      
 
ixed      
   
json    
ldap
mailparse      
 
mbstring      
mcrypt
   
memcache
       
memcached
 
mongo
       
mongodb      
msgpack    
 
mssql
       
mysql
       
mysqli
mysqlnd
newrelic    
       
oauth      
odbc
opcache  
pdo
pdo_dblib
pdo_firebird
pdo_mysql
pdo_odbc
pdo_pgsql
pdo_sqlite
pdo_sqlsrv      
 
pgsql
phar      
pinba
       
posix      
propro    
     
pspell
pthreads        
 
raphf    
     
readline
recode
redis
shmop      
simplexml      
snmp
soap      
sockets      
sodium          
spplus
         
sqlite3
sqlsrv      
 
ssh2
sysvmsg      
sysvsem      
sysvshm      
tideways      
 
tidy
tokenizer      
uuid        
wddx      
xcache
         
xdebug
 
xhprof
       
xml      
xmlreader      
xmlrpc
xmlwriter      
xsl
yaml        
zbarcode      
zendopcache
           
zip      

Note

Get the up-to-date complete list of extensions running this command after you SSH into your environment: ls /etc/php/*/mods-available (for PHP 5 run ls /etc/php5/mods-available).

Custom PHP Extensions

You can also use a not-listed PHP extension by following these steps:

  1. Download the .so file for the extension as part of your build hook using curl or similar.

    Note

    Alternatively, if the file is not publicly downloadable, you can also build the extension in your build section (although this means rebuilding the same extension on every deployment) or add the file to your Git repository (although committing large binary blobs to Git is generally not recommended).

  2. Edit your php.ini file in the application root (as a sibling of your .symfony.cloud.yaml file) that loads the extension using its absolute path:

    1
    2
    ; php.ini
    extension=/app/myextension.so
    

Alternate Start Command

Although PHP runs using PHP-FPM by default, you can also start alternative processes if desired, such as if you're running an Async PHP daemon, a thread-based worker process, etc. To do so, define an alternative start command in the main config file:

1
2
3
4
5
6
7
# .symfony.cloud.yaml
web:
    commands:
        start: 'php run.php'
    upstream:
        socket_family: tcp
        protocol: http

The above configuration will execute the run.php script in the application root when the container starts, but will not launch PHP-FPM. It will also tell the front-controller (Nginx) to connect to your application via a TCP socket, which will be specified in the PORT environment variable. Note that the start command must run in the foreground.

Note

Note that PHP-FPM cannot run simultaneously along with another persistent process (such as ReactPHP or Amp). If you need both they will have to run in separate containers.

PHP Worker Sizing Hints

The number of workers of a PHP runtime is set automatically and can be checked by running the following command:

1
2
$ symfony ssh -- find /etc/php -name php-fpm.conf -exec grep -e '^pm.max_children' {} \;
pm.max_children = 2

SymfonyCloud uses the following formula to calculate the number of workers:

1
2
3
              / Container Memory - Reserved Request Memory     \
workers = max|  ------------------------------------------- , 2 |
              \           Average Request Memory               /
Container Memory
The total memory available for the container, which depends on the size of the container.
Average Request Memory
The memory that an average request is expected to require. Default value: 45 MB.
Reserved Request Memory
The memory that should be reserved for things that are not specific to a request (memory for nginx, the op-code cache, some OS page cache, etc.) Default value: 70 MB.

You can tweak the default values if your application will typically consume more memory or if your application container is swapping a lot. To do so, set the following options in the main config file:

1
2
3
4
5
6
# .symfony.cloud.yaml
runtime:
    sizing_hints:
        # values are considered megabytes
        request_memory: 10
        reserved_memory: 70

The request_memory value must be 1 MB or higher and the reserved_memory value must be 70 MB or higher.

Measuring PHP Worker Memory Usage

To see how much memory your PHP worker processes are using, look at the PHP access log:

1
$ symfony log php.access

In the fifth column, you'll see the peak memory usage that occurred while each request was handled. A good way to determine an optimal request memory is with the following command:

1
$ tail -n5000 /var/log/php.access.log | awk '{print $6}' | sort -n | uniq -c

This will print out a table of how many requests used how much memory, in KB, for the last 5,000 requests that reached PHP-FPM (increase that number if your site has lot of traffic). As an example, consider the following output:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
4800 2048
 948 4096
 785 6144
 584 8192
 889 10240
 492 12288
 196 14336
  68 16384
   2 18432
   1 22528
   6 131072

This indicates that the majority of requests (4800) used 2048 KB of memory. In this case that's likely application caching at work. Most requests used up to around 10 MB of memory, while a few used as much as 18 MB and a very very few (6 requests) peaked at 131 MB.

A conservative approach would suggest an average request memory of 16 MB should be sufficient. A more aggressive stance would suggest 10 MB. The more aggressive approach would potentially allow for more concurrent requests at the risk of some requests needing to use swap memory, thus slowing them down.

Note

If you are running PHP 5.x then don't bother adjusting the worker memory usage until you upgrade to PHP 7.x. PHP 7 is way more memory efficient and you will likely need less than half as much memory per process with PHP7.

PHP Configuration

There are three ways to customize php.ini values for your application.

Option 1. Create a file called php.ini in the root directory of the application. This is the recommended method:

1
2
; php.ini
memory_limit = 256M

Option 2. Use the variables.php property of the main config file:

1
2
3
4
# .symfony.cloud.yaml
variables:
    php:
        memory_limit: 256M

Option 3. Define the values as env vars for some specific environment. This method is mostly useful on development environments to enable error outputting, enable the Xdebug extension, etc.:

1
$ symfony var:set php:memory_limit=256M

Error Handling

By default, display_errors is set to On to ease setting up your project. We strongly recommend providing a custom error handler in your application or setting this value to Off before you make your site live and this is done automatically for you during initial configuration using the project:init command:

  • INI
    1
    2
    ; php.ini
    display_errors=Off
    
  • YAML
    1
    2
    3
    4
    # .symfony.cloud.yaml
    variables:
        php:
            display_errors: Off
    

PHP Timezone

You can change the timezone of the PHP runtime with the following configuration:

  • INI
    1
    2
    ; php.ini
    date.timezone="Europe/Paris
    
  • YAML
    1
    2
    3
    4
    # .symfony.cloud.yaml
    variables:
        php:
            "date.timezone": "Europe/Paris"
    

Check out the main Timezone article to learn more about setting the timezone of other services.

Runtime configuration

In addition to PHP Configuration, SymfonyCloud also lets you configure the PHP-FPM runtime via the runtime section on the .symfony.cloud.yaml file. The following options are configurable:

  • request_terminate_timeout: The timeout for serving a single request after which the PHP-FPM worker process will be killed. This option should be used when the max_execution_time ini option does not stop script execution for some reason.

    1
    2
    3
    # .symfony.cloud.yaml
    runtime:
        request_terminate_timeout: 300
    
  • sizing_hints: Hints given to SymfonyCloud to compute the optimal number of workers serving HTTP requests. See PHP Worker Sizing Hints for more information.

    1
    2
    3
    4
    5
    6
    # .symfony.cloud.yaml
    runtime:
        sizing_hints:
            # values are considered megabytes
            request_memory: 10
            reserved_memory: 70
    

Debug PHP-FPM

Use the env:fpm:status command to inspect what's going on with PHP-FPM:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
$ symfony env:fpm:status

pool:                 web
process manager:      ondemand
start time:           10/Jan/2019:08:55:43 +0000
start since:          365469
accepted conn:        17329
listen queue:         0
max listen queue:     0
listen queue len:     0
idle processes:       0
active processes:     1
total processes:      1
max active processes: 2
max children reached: 102
slow requests:        0

************************
pid:                  20216
state:                Running
start time:           14/Jan/2019:14:26:14 +0000
start since:          38
requests:             3
request duration:     155
request method:       GET
request URI:          /-/status?&full
content length:       0
user:                 -
script:               -
last request cpu:     0.00
last request memory:  0

This work, including the code samples, is licensed under a Creative Commons BY-SA 3.0 license.