Known Issues

Fibers

Calling PHP functions and language constructs that themselves call cgo in Fibers is known to cause crashes.

This issue is being worked on by the Go project.

In the meantime, one solution is not to use constructs (like echo) and functions (like header()) that delegate to Go from inside Fibers.

This code will likely crash because it uses echo in the Fiber:

  1. $fiber = new Fiber(function() {
  2. echo 'In the Fiber'.PHP_EOL;
  3. echo 'Still inside'.PHP_EOL;
  4. });
  5. $fiber->start();

Instead, return the value from the Fiber and use it outside:

  1. $fiber = new Fiber(function() {
  2. Fiber::suspend('In the Fiber'.PHP_EOL));
  3. Fiber::suspend('Still inside'.PHP_EOL));
  4. });
  5. echo $fiber->start();
  6. echo $fiber->resume();
  7. $fiber->resume();

Unsupported PHP Extensions

The following extensions are known not to be compatible with FrankenPHP:

NameReasonAlternatives
imapNot thread-safejavanile/php-imap2, webklex/php-imap
newrelicNot thread-safe-

Buggy PHP Extensions

The following extensions have known bugs and unexpected behaviors when used with FrankenPHP:

NameProblem
ext-opensslWhen using a static build of FrankenPHP (built with the musl libc), the OpenSSL extension may crash under heavy loads. A workaround is to use a dynamically linked build (like the one used in Docker images). This bug is being tracked by PHP.

get_browser

The get_browser() function seems to perform badly after a while. A workaround is to cache (e.g. with APCu) the results per User Agent, as they are static.

Standalone Binary and Alpine-based Docker Images

The standalone binary and Alpine-based docker images (dunglas/frankenphp:*-alpine) use musl libc instead of glibc and friends, to keep a smaller binary size. This may lead to some compatibility issues. In particular, the glob flag GLOB_BRACE is not available

Using https://127.0.0.1 with Docker

By default, FrankenPHP generates a TLS certificate for localhost. It’s the easiest and recommended option for local development.

If you really want to use 127.0.0.1 as a host instead, it’s possible to configure it to generate a certificate for it by setting the server name to 127.0.0.1.

Unfortunately, this is not enough when using Docker because of its networking system. You will get a TLS error similar to curl: (35) LibreSSL/3.3.6: error:1404B438:SSL routines:ST_CONNECT:tlsv1 alert internal error.

If you’re using Linux, a solution is to use the host networking driver:

  1. docker run \
  2. -e SERVER_NAME="127.0.0.1" \
  3. -v $PWD:/app/public \
  4. --network host \
  5. dunglas/frankenphp

The host networking driver isn’t supported on Mac and Windows. On these platforms, you will have to guess the IP address of the container and include it in the server names.

Run the docker network inspect bridge and look at the Containers key to identify the last currently assigned IP address under the IPv4Address key, and increment it by one. If no container is running, the first assigned IP address is usually 172.17.0.2.

Then, include this in the SERVER_NAME environment variable:

  1. docker run \
  2. -e SERVER_NAME="127.0.0.1, 172.17.0.3" \
  3. -v $PWD:/app/public \
  4. -p 80:80 -p 443:443 -p 443:443/udp \
  5. dunglas/frankenphp

Caution

Be sure to replace 172.17.0.3 with the IP that will be assigned to your container.

You should now be able to access https://127.0.0.1 from the host machine.

If that’s not the case, start FrankenPHP in debug mode to try to figure out the problem:

  1. docker run \
  2. -e CADDY_GLOBAL_OPTIONS="debug" \
  3. -e SERVER_NAME="127.0.0.1" \
  4. -v $PWD:/app/public \
  5. -p 80:80 -p 443:443 -p 443:443/udp \
  6. dunglas/frankenphp

Composer Scripts Referencing @php

Composer scripts may want to execute a PHP binary for some tasks, e.g. in a Laravel project to run @php artisan package:discover --ansi. This currently fails for two reasons:

  • Composer does not know how to call the FrankenPHP binary;
  • Composer may add PHP settings using the -d flag in the command, which FrankenPHP does not yet support.

As a workaround, we can create a shell script in /usr/local/bin/php which strips the unsupported parameters and then calls FrankenPHP:

  1. #!/usr/bin/env bash
  2. args=("$@")
  3. index=0
  4. for i in "$@"
  5. do
  6. if [ "$i" == "-d" ]; then
  7. unset 'args[$index]'
  8. unset 'args[$index+1]'
  9. fi
  10. index=$((index+1))
  11. done
  12. /usr/local/bin/frankenphp php-cli ${args[@]}

Then set the environment variable PHP_BINARY to the path of our php script and run Composer:

  1. export PHP_BINARY=/usr/local/bin/php
  2. composer install

Troubleshooting TLS/SSL Issues with Static Binaries

When using the static binaries, you may encounter the following TLS-related errors, for instance when sending emails using STARTTLS:

  1. Unable to connect with STARTTLS: stream_socket_enable_crypto(): SSL operation failed with code 5. OpenSSL Error messages:
  2. error:80000002:system library::No such file or directory
  3. error:80000002:system library::No such file or directory
  4. error:80000002:system library::No such file or directory
  5. error:0A000086:SSL routines::certificate verify failed

As the static binary doesn’t bundle TLS certificates, you need to point OpenSSL to your local CA certificates installation.

Inspect the output of openssl_get_cert_locations(), to find where CA certificates must be installed and store them at this location.

Warning

Web and CLI contexts may have different settings. Be sure to run openssl_get_cert_locations() in the proper context.

CA certificates extracted from Mozilla can be downloaded on the curl site.

Alternatively, many distributions, including Debian, Ubuntu, and Alpine provide packages named ca-certificates that contain these certificates.

It’s also possible to use the SSL_CERT_FILE and SSL_CERT_DIR to hint OpenSSL where to look for CA certificates:

  1. # Set TLS certificates environment variables
  2. export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
  3. export SSL_CERT_DIR=/etc/ssl/certs