Alexander Stecher
9cfa7b3f65
fix: opcache_preload in PHP 8.2 ( #2284 )
...
Fixes the Docker image tests currently failing in CI.
2026-03-17 11:14:45 +07:00
Marc
2895273476
perf: extend table on env startup instead of letting zend_hash_copy do it ( #2272 )
...
this can potentially save us a few internal calls to zend_hash_do_resize
while it loops over the source table (main_thread_env)
`8 -> 16 -> 32 -> 64 -> 128` becomes `8 -> target_size (rounded to power
of 2) 128`.
2026-03-12 22:23:39 +07:00
Marc
5979b4dac7
fix php startup errors when ini files contain environment variables ( #2252 )
...
closes #2250
---------
Signed-off-by: Marc <m@pyc.ac >
Co-authored-by: Kévin Dunglas <kevin@dunglas.fr >
2026-03-08 22:28:14 +07:00
Alexander Stecher
356d2e1745
refactor: cleaner cgi string handling
...
Introduces C-side interned string registry (frankenphp_strings) and a frankenphp_server_vars struct to bulk-register known $_SERVER variables with pre-sized hashtable capacity.
2026-03-04 17:20:24 +01:00
Kévin Dunglas
cda58d224b
fix(windows): ensure DLLs can always be located by PHP ( #2227 )
...
Prevent crashes when `php.ini` references PHP extensions using relative
paths, and FrankenPHP is started from a different working directory than
the one containing extensions, or with `caddy start` (instead of `caddy
run`).
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com >
2026-03-02 18:27:30 +01:00
Alexander Stecher
8f4412cbbf
perf: move sandboxed environment to the C side ( #2058 )
...
This PR uses `zend_array_dup` to simplify and optimize the environment sandboxing
logic. It also guarantees no environment leakage on FrankenPHP restarts.
2026-02-26 22:34:54 +01:00
Kévin Dunglas
25ed020036
feat: Windows support ( #2119 )
...
Closes #83 #880 #1286 .
Working patch for Windows support.
Supports linking to the [official PHP release (TS
version)](https://www.php.net/downloads.php ).
Includes some work from #1286 (thanks @TenHian!!)
This patch allows using Visual Studio to compile the cgo code. To do so,
it must be compiled with Go 1.26 (RC) with the following setup:
```powershell
winget install -e --id Microsoft.VisualStudio.2022.Community --override "--passive --wait --add Microsoft.VisualStudio.Workload.NativeDesktop --add Microsoft.VisualStudio.Component.VC.Llvm.Clang --includeRecommended"
winget install -e --id GoLang.Go
$env:PATH += ';C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\Llvm\bin'
cd c:\
gh repo clone microsoft/vcpkg
.\vcpkg\bootstrap-vcpkg.bat
.\vcpkg\vcpkg install pthreads brotli
# build watcher
Invoke-WebRequest -Uri "https://github.com/e-dant/watcher/releases/download/0.14.3/x86_64-pc-windows-msvc.tar " -OutFile "$env:TEMP\watcher.tar"
tar -xf "$env:TEMP\watcher.tar" -C C:\
Rename-Item -Path "C:\x86_64-pc-windows-msvc" -NewName "watcher-x86_64-pc-windows-msvc"
Remove-Item "$env:TEMP\watcher.tar"
# download php
Invoke-WebRequest -Uri "https://downloads.php.net/~windows/releases/archives/php-8.5.1-Win32-vs17-x64.zip " -OutFile "$env:TEMP\php.zip"
Expand-Archive -Path "$env:TEMP\php.zip" -DestinationPath "C:\"
Remove-Item "$env:TEMP\php.zip"
# download php development package
Invoke-WebRequest -Uri "https://downloads.php.net/~windows/releases/archives/php-devel-pack-8.5.1-Win32-vs17-x64.zip " -OutFile "$env:TEMP\php-devel.zip"
Expand-Archive -Path "$env:TEMP\php-devel.zip" -DestinationPath "C:\"
Remove-Item "$env:TEMP\php-devel.zip"
$env:GOTOOLCHAIN = 'go1.26rc1'
$env:CC = 'clang'
$env:CXX = 'clang++'
$env:CGO_CFLAGS = "-I$env:C:\vcpkg\installed\x64-windows\include -IC:\watcher-x86_64-pc-windows-msvc -IC:\php-8.5.1-devel-vs17-x64\include -IC:\php-8.5.1-devel-vs17-x64\include\main -IC:\php-8.5.1-devel-vs17-x64\include\TSRM -IC:\php-8.5.1-devel-vs17-x64\include\Zend -IC:\php-8.5.1-devel-vs17-x64\include\ext"
$env:CGO_LDFLAGS = '-LC:\vcpkg\installed\x64-windows\lib -lbrotlienc -LC:\watcher-x86_64-pc-windows-msvc -llibwatcher-c -LC:\php-8.5.1-Win32-vs17-x64 -LC:\php-8.5.1-devel-vs17-x64\lib -lphp8ts -lphp8embed'
# clone frankenphp and build
git clone -b windows https://github.com/php/frankenphp.git
cd frankenphp\caddy\frankenphp
go build -ldflags '-extldflags="-fuse-ld=lld"' -tags nowatcher,nobadger,nomysql,nopgx
# Tests
$env:PATH += ";$env:VCPKG_ROOT\installed\x64-windows\bin;C:\watcher-x86_64-pc-windows-msvc";C:\php-8.5.1-Win32-vs17-x64"
"opcache.enable=0`r`nopcache.enable_cli=0" | Out-File -Encoding ascii php.ini
$env:PHPRC = Get-Location
go test -ldflags '-extldflags="-fuse-ld=lld"' -tags nowatcher,nobadger,nomysql,nopgx .
```
TODO:
- [x] Fix remaining skipped tests (scaling and watcher)
- [x] Test if the watcher mode works as expected
- [x] Automate the build with GitHub Actions
---------
Signed-off-by: Marc <m@pyc.ac >
Co-authored-by: Kévin Dunglas <kevin@dunglas.dev >
Co-authored-by: DubbleClick <m@pyc.ac >
2026-02-26 12:38:14 +01:00
Kévin Dunglas
681aae60a6
fix(worker): revert ini reset, keep session fixes ( #2139 )
...
Revert the INI snapshot/restore mechanism from #2139 which caused
issues with frameworks that lazily set ini values like session.save_path
(#2185 ). Replace the session handler snapshot/restore with a simpler
direct session state reset from #2193 , which preserves mod_user_names
across requests without requiring session module reload.
Co-Authored-By: Xavier Leune <xavier.leune@gmail.com >
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com >
2026-02-23 14:02:20 +01:00
Alexander Stecher
b02d99ae8a
feat: always ignore user abort ( #2189 )
...
Automatically sets `ignore_user_abort` to true in worker mode as
mentioned in #2186 , removing the requirement to change it via ini.
Would also be possible to expose something like an explicit
`frankenphp_client_has_closed()` function for in-between critical
sections.
---------
Co-authored-by: Marc <m@pyc.ac >
2026-02-19 11:55:39 +01:00
Xavier Leune
24d6c991a7
fix(worker): session leak between requests
2026-02-11 12:12:52 +01:00
Kévin Dunglas
db59edb590
ci: fix shellcheck errors and improve consistency ( #2165 )
2026-02-05 12:48:25 +01:00
Xavier Leune
ad7e4f146d
fix(worker): reset ini settinfs and session if changed during worker request
2026-02-03 16:27:35 +01:00
Xavier Leune
0e8de8f56f
fix(worker): initialize $_RESUEST ( #2136 )
...
Hi,
This PR fixes #1931 , it handles $_REQUEST in worker mode correctly when
`auto_globals_jit` is enabled (default configuration for PHP).
Some concerns were raised in the comments of the issue regarding
performance. This implementation should make sure that request is
created only if used.
However if a previous execution plan already used `_REQUEST`, all
subsequent requests will create it. So the concern is "kindof"
mitigated.
Let me know if you have any suggestion to improve this.
---------
Signed-off-by: Xavier Leune <xavier.leune@gmail.com >
Co-authored-by: Alexander Stecher <45872305+AlliBalliBaba@users.noreply.github.com >
2026-01-29 06:56:45 +01:00
Alexander Stecher
0c2a0105b5
fix: let PHP handle basic auth. ( #2142 )
...
I noticed that PHP likes to handle and free basic auth parameters
internally (see
[here](9f774e3a85/main/main.c (L2739) )
and
[here](9f774e3a85/main/SAPI.c (L514-L525) )).
This PR changes it so the basic auth header is forwarded to PHP instead
of resolving it in go.
I suspect that this might fix some crashes in shutdown functions (like
#2121 and #1841 ) since it allows us freeing the `request_info` after
shutdown is finished. I haven't been able to reproduce these crashes yet
though.
2026-01-26 10:42:32 +01:00
YL
11160fb7b3
fix: segmentation fault when registering multiple extensions ( #2112 )
...
This PR fixes a segmentation fault when using
frankenphp.RegisterExtension with more than one extension.
The issue was a type mismatch between Go and C: Go passes a slice of
pointers, but the C code was treating it as a contiguous array of
structs. This caused invalid memory access when iterating past the first
element.
I created a minimal reproduction repo here:
[https://github.com/y-l-g/frankenphp-extensions-segfault-repro ](https://www.google.com/url?sa=E&q=https%3A%2F%2Fgithub.com%2Fy-l-g%2Ffrankenphp-extensions-segfault-repro )
2026-01-07 09:21:03 +01:00
Kévin Dunglas
4092ecb5b5
fix: frankenphp_log() level parameter must be optional
2025-12-19 16:25:32 +01:00
Raphael Coeffic
91c553f3d9
feat: add support for structured logging with the frankenphp_log() PHP function ( #1979 )
...
As discussed in https://github.com/php/frankenphp/discussions/1961 ,
there is no real way to pass a severity/level to any log handler offered
by PHP that would make it to the FrankenPHP layer. This new function
allows applications embedding FrankenPHP to integrate PHP logging into
the application itself, thus offering a more streamlined experience.
---------
Co-authored-by: Quentin Burgess <qutn.burgess@gmail.com >
Co-authored-by: Kévin Dunglas <kevin@dunglas.fr >
2025-12-15 16:10:35 +01:00
Alexander Stecher
98573ed7c0
refactor: extract the state module and make the backoff error instead of panic
...
This PR:
- moves state.go to its own module
- moves the phpheaders test the phpheaders module
- simplifies backoff.go
- makes the backoff error instead of panic (so it can be tested)
- removes some unused C structs
2025-12-02 23:10:12 +01:00
Kévin Dunglas
41e0713a1b
fix: allow null for mercure_publish() retry parameter
2025-11-21 13:52:55 +01:00
Kévin Dunglas
41cb2bbeaa
feat: mercure_publish() PHP function to dispatch Mercure updates ( #1927 )
...
* feat: mercure_publish() PHP function to dispatch Mercure updates
* fix stubs for old versions
* review
* cleanup and fixes
2025-11-18 09:59:53 +01:00
Kévin Dunglas
8341cc98c6
refactor: rely on context.Context for log/slog and others ( #1969 )
...
* refactor: rely on context.Context for log/slog and others
* optimize
* refactor
* Apply suggestion from @Copilot
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com >
* fix watcher-skip
* better globals handling
* fix
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com >
2025-11-17 16:32:23 +01:00
Alexander Stecher
bf6e6534f6
fix: exit() and dd() support in worker mode ( #1946 )
...
* Verifies exit behavior.
* formatting
* Checks for actual exit.
* Fixes test.
* Fixes test.
* Update testdata/dd.php
Co-authored-by: Kévin Dunglas <kevin@dunglas.fr >
---------
Co-authored-by: Kévin Dunglas <kevin@dunglas.fr >
2025-10-28 10:57:50 +01:00
SpencerMalone
1f6f768c97
fix: release but don't free CLI streams when executing cli scripts ( #1906 )
...
* Bring upstream commit 0a4a55fd44 into cli_register_file_handles to release but not free stdout/in/err.
Fixes being unable to log to stdout or error after using frankenphp.ExecutePHPCode
* chore: clang-format
---------
Co-authored-by: Kévin Dunglas <kevin@dunglas.fr >
2025-10-08 17:07:54 +02:00
Rob Landers
52df300f86
feat: custom workers initial support ( #1795 )
...
* create a simple thread framework
Signed-off-by: Robert Landers <landers.robert@gmail.com >
* add tests
Signed-off-by: Robert Landers <landers.robert@gmail.com >
* fix comment
Signed-off-by: Robert Landers <landers.robert@gmail.com >
* remove mention of an old function that no longer exists
Signed-off-by: Robert Landers <landers.robert@gmail.com >
* simplify providing a request
Signed-off-by: Robert Landers <landers.robert@gmail.com >
* satisfy linter
Signed-off-by: Robert Landers <landers.robert@gmail.com >
* add error handling and handle shutdowns
Signed-off-by: Robert Landers <landers.robert@gmail.com >
* add tests
Signed-off-by: Robert Landers <landers.robert@gmail.com >
* pipes are tied to workers, not threads
Signed-off-by: Robert Landers <landers.robert@gmail.com >
* fix test
Signed-off-by: Robert Landers <landers.robert@gmail.com >
* add a way to detect when a request is completed
Signed-off-by: Robert Landers <landers.robert@gmail.com >
* we never shutdown workers or remove them, so we do not need this
Signed-off-by: Robert Landers <landers.robert@gmail.com >
* add more comments
Signed-off-by: Robert Landers <landers.robert@gmail.com >
* Simplify modular threads (#1874 )
* Simplify
* remove unused variable
* log thread index
* feat: allow passing parameters to the PHP callback and accessing its return value (#1881 )
* fix formatting
Signed-off-by: Robert Landers <landers.robert@gmail.com >
* fix test compilation
Signed-off-by: Robert Landers <landers.robert@gmail.com >
* fix segfaults
Signed-off-by: Robert Landers <landers.robert@gmail.com >
* Update frankenphp.c
Co-authored-by: Kévin Dunglas <kevin@dunglas.fr >
---------
Signed-off-by: Robert Landers <landers.robert@gmail.com >
Co-authored-by: Kévin Dunglas <kevin@dunglas.fr >
2025-09-18 09:21:49 +02:00
Alexander Stecher
78bc5c87d8
fix: free request context if php_request_startup() errors ( #1842 )
2025-08-28 17:29:10 +02:00
Alexander Stecher
952754db27
fix: don't flush env between requests ( #1814 )
2025-08-27 08:30:40 +02:00
Alexander Stecher
c10e85b905
refactor: cleanup context ( #1816 )
...
* Removes NewRequestWithContext.
* Moves cgi logic to cgi.go
* Calls 'update_request_info' from the C side.
* Calls 'update_request_info' from the C side.
* clang-format
* Removes unnecessary export.
* Adds TODO.
* Adds TODO.
* Removes 'is_worker_thread'
* Shortens return statement.
* Removes the context refactor.
* adjusts comment.
* Skips parsing cgi path variables on explicitly assigned worker.
* suggesions by @dunglas.
* Re-introduces 'is_worker_thread'.
* More formatting.
2025-08-25 16:18:20 +02:00
Alexandre Daubois
8175ae7e8c
chore: miscellaneous fix in C code ( #1766 )
2025-07-24 10:24:38 +02:00
Alexandre Daubois
b80cb6cdea
chore: cleanup duplication in sapi_cli_register_variables() ( #1716 )
2025-07-05 19:05:38 +02:00
Alexandre Daubois
29c88c0fec
feat: use modern ZEND_PARSE_PARAMETERS_NONE() macro ( #1704 )
2025-06-30 14:50:11 +02:00
Alexandre Daubois
8d88c13795
chore: remove TODO items not relevant anymore ( #1694 )
2025-06-27 14:36:09 +02:00
Alexandre Daubois
d2a1b619a5
feat: expose SSL_CIPHER env var ( #1693 )
2025-06-27 14:27:20 +02:00
Kévin Dunglas
abfd893d88
feat: FrankenPHP extensions ( #1651 )
...
* feat: add helpers to create PHP extensions (#1644 )
* feat: add helpers to create PHP extensions
* cs
* feat: GoString
* test
* add test for RegisterExtension
* cs
* optimize includes
* fix
* feat(extensions): add the PHP extension generator (#1649 )
* feat(extensions): add the PHP extension generator
* unexport many types
* unexport more symbols
* cleanup some tests
* unexport more symbols
* fix
* revert types files
* revert
* add better validation and fix templates
* remove GoStringCopy
* small fixes
---------
Co-authored-by: Kévin Dunglas <kevin@dunglas.fr >
* try to fix tests
* fix CS
* try some workarounds
* try some workarounds
* ingore TestRegisterExtension
* exclude cgo tests in Docker images
* fix
* workaround...
* race detector
* simplify tests and code
* make linter happy
* feat(gofile): use templates to generate the Go file (#1666 )
---------
Co-authored-by: Alexandre Daubois <2144837+alexandre-daubois@users.noreply.github.com >
2025-06-25 10:18:22 +02:00
Rob Landers
a59b649dac
fix: headers before flushing ( #1622 )
...
* add tests
* fix test
* attempt to send headers when flushing
* Update testdata/only-headers.php
Co-authored-by: Kévin Dunglas <kevin@dunglas.fr >
---------
Co-authored-by: Kévin Dunglas <kevin@dunglas.fr >
2025-06-01 14:58:36 +02:00
Kévin Dunglas
c522b52804
fix: exit(), die() and uncaught exceptions must stop the worker
2025-05-21 01:19:22 +02:00
Alexander Stecher
3741782330
feat: '-r' option for php-cli ( #1482 )
2025-05-01 02:06:31 +02:00
Pierre Tondereau
729cf9bba1
fix: module reload on request startup ( #1476 )
2025-04-01 20:54:24 +02:00
Gina Peter Banyard
3701516e5e
refactor: call opcache_reset PHP function directly ( #1401 )
...
* Call opcache_reset PHP function directly
* prevent warning
* cleanup
* remove frankenphp_execute_php_function
* cs
---------
Co-authored-by: Kévin Dunglas <kevin@dunglas.fr >
2025-03-24 11:29:13 +01:00
Alexander Stecher
432824edf1
fix: ensure env is not in an invalid state on shutdown ( #1442 )
2025-03-19 13:22:06 +01:00
Kévin Dunglas
424ca426cb
fix: timeouts handling on macOS ( #1435 )
...
* ci: run tests on macOS
* debug
* debug
* fix
* nobrotli
* install brotli
* fix
* fix
* Also registers php.ini if ZEND_MAX_EXECUTION_TIMERS is disabled.
* Removes max_execution_time from tests (it gets overwritten on mac)
* tiny refacto
* fix free
* cs
---------
Co-authored-by: Alliballibaba <alliballibaba@gmail.com >
2025-03-11 17:34:49 +01:00
Alexander Stecher
f50248a7d2
refactor: removes context on the C side ( #1404 )
2025-03-10 08:44:03 +01:00
Alexander Stecher
c57f741d83
fix: concurrent env access ( #1409 )
2025-03-01 14:45:04 +01:00
Alliballibaba2
072151dfee
feat: Adds automatic thread scaling at runtime and php_ini configuration in Caddyfile ( #1266 )
...
Adds option to scale threads at runtime
Adds php_ini configuration in Caddyfile
2025-02-19 20:39:33 +01:00
Kévin Dunglas
251567a617
fix: Mercure duplicate metrics panic ( #1393 )
...
* fix: Mercure duplicate metrics panic
* tidy
* ci: clang-format
2025-02-19 12:40:59 +01:00
Niels Dossche
f109f0403b
perf: avoid redundant work in frankenphp_release_temporary_streams()
...
Persistent streams are of type le_pstream, not le_stream. Therefore, the
persistent check will always be false. We can thus replace that check
with an assertion.
`zend_list_delete` removes the entry from the regular_list table, and
calls `zend_resource_dtor` via the table destructor.
When the refcount is 1, `zend_list_close` calls `zend_resource_dtor`,
but keeps the entry in the table.
Multiple calls to `zend_resource_dtor` have no effect: the destructor is
only called once.
Therefore, the `zend_list_close` operation is redundant because it is
fully included in the work done by `zend_list_delete`.
2025-02-19 00:16:00 +01:00
Niels Dossche
30bf69cbe5
perf: avoid extra string allocation in get_full_env() ( #1382 )
...
* Avoid extra string allocation in get_full_env()
We can pass the key directly to add_assoc_str().
* Use add_assoc_str_ex
2025-02-18 09:11:23 +01:00
Alexander Stecher
dd250e3bda
perf: optimized request headers ( #1335 )
...
* Optimizes header registration.
* Adds malformed cookie tests.
* Sets key to NULL (releasing them is unnecessary)
* Adjusts test.
* Sanitizes null bytes anyways.
* Sorts headers.
* trigger
* clang-format
* More clang-format.
* Updates headers and tests.
* Adds header test.
* Adds more headers.
* Updates headers again.
* ?Removes comments.
* ?Reformats headers
* ?Reformats headers
* renames header files.
* ?Renames test.
* ?Fixes assertion.
* test
* test
* test
* Moves headers test to main package.
* Properly capitalizes headers.
* Allows and tests multiple cookie headers.
* Fixes comment.
* Adds otter back in.
* Verifies correct capitalization.
* Resets package version.
* Removes debug log.
* Makes persistent strings also interned and saves them once on the main thread.
---------
Co-authored-by: Alliballibaba <alliballibaba@gmail.com >
2025-01-27 21:48:20 +01:00
Alexander Stecher
7e39e0a201
Fix: only flush temporary unreferenced streams ( #1351 )
...
* Only flush temporary streams.
---------
Co-authored-by: Alliballibaba <alliballibaba@gmail.com >
2025-01-27 00:25:12 +01:00
Rob Landers
05aafc7c44
fix memory leaks ( #1350 )
...
* fix a memory leak on thread shutdown
* clean up unused resources at end of request
* try the obvious
* Test
* clang-format
* Also ignores persistent streams.
* Adds stream test.
* Moves clean up function to frankenphp_worker_request_shutdown.
* Fixes test on -nowatcher
* Fixes test on -nowatcher
* Update testdata/file-stream.txt
Co-authored-by: Kévin Dunglas <kevin@dunglas.fr >
* Update frankenphp_test.go
Co-authored-by: Kévin Dunglas <kevin@dunglas.fr >
---------
Co-authored-by: Alliballibaba <alliballibaba@gmail.com >
Co-authored-by: Kévin Dunglas <kevin@dunglas.fr >
2025-01-25 22:54:04 +01:00
Viktor Szépe
eee1de147e
chore: fix CS ( #1345 )
2025-01-21 11:27:46 +01:00