github php/frankenphp v1.13.0

3 hours ago

FrankenPHP 1.13.0 is a big one. It upgrades to Caddy 2.11.7, bringing Slowloris protection, the new url_pattern matcher, the Incremental header for streaming apps and many reverse proxy fixes. It ships with Mercure 1.0, the stable version of the real-time protocol. Configuration reloads are now safe: an invalid configuration is rejected before it replaces the running one, instead of leaving the server answering 500. This release also fixes 5 security vulnerabilities, 2 of them rated high. Upgrading is strongly recommended, and the upgrade notes below are worth a read first. Need help with the upgrade or with sizing threads and workers? Les-Tilleuls.coop, the company behind FrankenPHP, provides professional support, performance audits, custom development and training: contact@les-tilleuls.coop.

🔒 Security

  • High: Fix a document-root escape in SCRIPT_FILENAME resolution on Windows (GHSA-868c-7h7m-mmj9).
  • High: Fix header spoofing through dot-form header names: PHP maps Foo.Bar to HTTP_FOO_BAR like Foo-Bar. Caddy 2.11.7 now drops such headers by default, and the NewRequestWithContext() documentation warns library users (GHSA-qcrp-8483-f2f2).
  • Require a path segment boundary when splitting the CGI path, so /uploads/a.php.txt/b.php no longer executes uploads/a.php (GHSA-xxjp-cjxr-2x6m).
  • putenv() no longer writes to the process-wide OS environment, which leaked values across requests and threads (GHSA-996f-w38m-f574).
  • Fix a crash of the whole server process when frankenphp_log() receives a crafted array (GHSA-4prg-hv4r-g6mv).

🌐 Caddy 2.11.7

FrankenPHP 1.12.7 shipped Caddy 2.11.4. This release includes everything from Caddy 2.11.6 and 2.11.7, including:

📡 Mercure 1.0

FrankenPHP embeds Mercure 1.0 by @dunglas in #2611:

  • mercure_publish() now throws a ValueError for invalid updates (topic in the reserved /.well-known/mercure namespace, ID starting with #, control characters, invalid UTF-8, negative retry, no topic) and a RuntimeException carrying the hub's message when the dispatch fails.
  • Publisher and subscriber keys are bound to a trusted issuer with the new issuer block. The sample Caddyfile and php-server --mercure use it.

⚠️ Upgrade Notes

  • num_threads now counts the threads for requests no worker serves; worker threads come on top. A configuration that sets num_threads with workers declared starts more threads than before. If max_threads is below num_threads plus the worker threads, startup now fails with an error naming the three numbers. Defaults are unchanged (#2660).
  • Mercure: setting publisher_jwt or subscriber_jwt without protocol_version_compatibility is now a configuration error. Bind keys to a trusted issuer with the new issuer block instead (see #2611 and the sample Caddyfile). Hot reloading follows the protocol: $_SERVER['FRANKENPHP_HOT_RELOAD'] now advertises /.well-known/mercure?match=<topic>, so update any URL hardcoded with ?topic=.
  • Caddy: request headers are now limited to 16 KiB by default (raise it with max_header_size), stalled reads and writes are aborted after 1 minute, headers containing . are dropped like those containing _ already were, a wildcard site's client_auth no longer applies to more specific sites, and some invalid configurations are now rejected. See the Caddy 2.11.6 breaking changes.
  • Building PHP without --disable-zend-signals (ZTS) now makes FrankenPHP refuse to start with an explicit error, instead of hanging while memory grows (#2639).

✨ New Features

  • Extensions: Expose a thread API for Go-based PHP extensions: Thread(index) to get the request bound to a PHP thread, PHPThread.Pin() to keep Go objects alive, PHPThread.IsRequestDone(), and the frankenphp_thread_index() C function by @johanjanssens in #2305.
  • Config reloads: Validate a configuration before it replaces the running one. A missing worker file, a duplicated worker name or an inconsistent thread budget is now rejected and the running configuration keeps serving. Library users get frankenphp.Validate() by @nicolas-grekas in #2661.
  • Threads: num_threads counts the threads left for regular requests, and the startup log reports total_threads and worker_threads by @nicolas-grekas in #2660.
  • Opcache: Log opcache shared-memory restarts and count them in the new experimental frankenphp_opcache_restarts{reason} metric (PHP 8.4+). These restarts are unsafe under ZTS, so the counter should stay at zero by @nicolas-grekas in #2634.
  • php_server: Mirror php_server blocks on the FrankenPHP side, so requests and workers are properly scoped to their block by @AlliBalliBaba in #2499.
  • phpinfo: phpinfo() now has a FrankenPHP section listing the Caddy version, and Go code can add rows with frankenphp.AddPHPInfoEntry() by @henderkes in #2578.
  • CLI: php-cli uses PHP's built-in CLI SAPI on PHP 8.5+ by @withinboredom in #1757.
  • PHP 8.6: Compatibility with PHP 8.6 by @henderkes in #2600.
  • Upgrade to Go 1.27 by @alexandre-daubois in #2626.

🐛 Bug Fixes

  • Startup: Don't hang requests that arrive before regular threads are ready, which showed up as random 499/504 errors on the first requests after a container start by @ptondereau in #2612.
  • Workers: Log worker crashes at warn level with their exit status, instead of debug like a clean restart by @luminalpark in #2602.
  • Shutdown: Fix Shutdown() hanging forever on a worker that gave up during boot past max_consecutive_failures by @nicolas-grekas in #2662 and #2664.
  • Static builds: Stop the bundled parallel extension from turning recoverable Go faults into process crashes by @henderkes in #2651. Fixes #2650.
  • Extensions: Fix a possible use-after-free of the extensions array retained by register_extensions by @henderkes in #2646. Fixes #2629.
  • extgen: Fix grouped and nullable parameters, callables, mixed return values, method wrappers, constants and integer literals in generated extensions by @alexandre-daubois in #2596.

📖 Documentation

  • List runtime engine settings that persist between requests in worker mode (ini_set(), stream_context_set_default(), date_default_timezone_set(), chdir()…) by @dunglas in #2682.
  • Document HTTP request filtering differences by @ousamabenyounes in #2561.
  • Enhance the metrics documentation by @alexandre-daubois in #2316.
  • Add a Yii 3 page by @KalimeroMK in #2615.
  • Fix the broken Idiomorph CDN URL in the hot reload snippet by @quyt0 in #2642.
  • Add missing Turkish translations by @mertingen in #2663.

💖 New Contributors

Full Changelog: v1.12.7...v1.13.0

Don't miss a new frankenphp release

NewReleases is sending notifications on new releases.