fix: set $_SERVER variables: 'SCRIPT_NAME', 'PHP_SELF', and 'PATH_INFO' #2317
fix: set $_SERVER variables: 'SCRIPT_NAME', 'PHP_SELF', and 'PATH_INFO' #2317
Conversation
…rkers apache passes PHP_SELF as SCRIPT_NAME + REQUEST_URL, but the docs say it's the same as SCRIPT_NAME and that's how Caddy+fpm behave too
cgi.go
Outdated
| // If a worker is already assigned explicitly, derive SCRIPT_NAME from its filename | ||
| if fc.worker != nil { | ||
| fc.scriptFilename = fc.worker.fileName | ||
| fc.scriptName = strings.TrimPrefix(fc.worker.fileName, fc.documentRoot) |
There was a problem hiding this comment.
Hmm probably would be better to leave scriptName empty if the worker is in the public path:
root /some/path
worker /other/path {
match *
}There was a problem hiding this comment.
I'm not sure about that. Shouldn't it show /other/path/index.php then?
There was a problem hiding this comment.
Not sure either TBH. In CGI spec it's the path relative to the root, so /other/path/index.php might be misleading.
There was a problem hiding this comment.
Technically that's a path relative to the root, haha.
I don't see a better solution. Emptying it out would be even more of a violation.
… would activate for the non-worker case too
Co-authored-by: Marc <m@pyc.ac> Signed-off-by: Marc <m@pyc.ac>
dunglas
left a comment
There was a problem hiding this comment.
LGTM, but I didn't carefully review the CGI spec nor existing Apache/FPM behaviors. I trust you on this
| ignore_user_abort(true); | ||
|
|
||
| $handler = static function() { | ||
| echo "SCRIPT_NAME: " . ($_SERVER['SCRIPT_NAME'] ?? '(not set)') . "<br>"; |
There was a problem hiding this comment.
Nit: you could add \n at the end of each lines, so you could use backticks for better readability in tests
| @@ -1,6 +1,8 @@ | |||
| /caddy/frankenphp/Build | |||
There was a problem hiding this comment.
added these because I often times find myself verifying bug reports there
I'm thinking they're fine in the .gitignore, but if you want I can revert
There was a problem hiding this comment.
Pull request overview
This PR fixes inconsistencies in $_SERVER CGI variables (notably SCRIPT_NAME, PHP_SELF, and PATH_INFO) in worker mode by ensuring path splitting happens consistently and by preserving “remainder” path segments through the Caddy rewrite/matching pipeline.
Changes:
- Always split CGI path variables during request context creation, including in worker mode.
- Set
PHP_SELFfromSCRIPT_NAME + PATH_INFO, and update CGI path splitting logic for worker-assigned requests. - Update Caddy
php_serverrewrite/match patterns to preserve remainder path info and add regression tests for server globals.
Reviewed changes
Copilot reviewed 7 out of 8 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
context.go |
Always calls splitCgiPath(fc) to compute CGI path vars consistently. |
cgi.go |
Updates PHP_SELF derivation and refactors splitCgiPath to better support worker mode. |
caddy/php-server.go |
Preserves remainder in rewrite and matches *.php/* paths to support PATH_INFO. |
caddy/module.go |
Same Caddy rewrite/matcher adjustments for the directive parser output. |
caddy/caddy_test.go |
Adds coverage asserting expected globals for both worker and non-worker php_server setups. |
testdata/server-globals.php |
New test helper script that prints key $_SERVER variables. |
.github/workflows/tests.yaml |
Adds -failfast to speed up CI failure feedback. |
.gitignore |
Ignores additional generated Caddy test artifacts. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Marc <m@pyc.ac>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Marc <m@pyc.ac>
alexandre-daubois
left a comment
There was a problem hiding this comment.
LGTM once Kevin's comments are addressed
| @@ -208,17 +208,25 @@ func splitCgiPath(fc *frankenPHPContext) { | |||
| if splitPos := splitPos(path, splitPath); splitPos > -1 { | |||
| fc.docURI = path[:splitPos] | |||
There was a problem hiding this comment.
Just realized the same is true for documentUri (should be empty with match), probably makes sense to move the worker check before this block.
There was a problem hiding this comment.
I didn't even know that's a server variable. Will move the check up later.
fixes #2274 (comment)
apache/nginx/caddy pass PHP_SELF as SCRIPT_NAME + PATH_INFO, but our PATH_INFO wasn't working because our matcher stripped the rest of the path.
request url: localhost/index.php/en