Skip to content

fix: set $_SERVER variables: 'SCRIPT_NAME', 'PHP_SELF', and 'PATH_INFO' #2317

Open
henderkes wants to merge 18 commits intomainfrom
fix/script_name
Open

fix: set $_SERVER variables: 'SCRIPT_NAME', 'PHP_SELF', and 'PATH_INFO' #2317
henderkes wants to merge 18 commits intomainfrom
fix/script_name

Conversation

@henderkes
Copy link
Copy Markdown
Contributor

@henderkes henderkes commented Mar 27, 2026

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

# was non-worker:
SCRIPT_NAME: /index.php
PATH_INFO: 
PHP_SELF: /index.php
REQUEST_URL: /en

# was fastcgi:
SCRIPT_NAME: /index.php
PATH_INFO:  /en
PHP_SELF: /index.php/en
REQUEST_URL: /en

# was php_server worker
SCRIPT_NAME:
PATH_INFO:
PHP_SELF: /en
REQUEST_URL: /en

# now is always:
SCRIPT_NAME: /index.php
PATH_INFO: /en
PHP_SELF: /index.php/en
REQUEST_URL: /en

…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
@henderkes henderkes requested a review from AlliBalliBaba March 27, 2026 15:49
@henderkes henderkes marked this pull request as ready for review March 27, 2026 15:49
@henderkes henderkes marked this pull request as draft March 27, 2026 16:26
@henderkes henderkes changed the title fix $_SERVER['SCRIPT_NAME'] and $_SERVER['PHP_SELF'] in php_server workers fix $_SERVER['SCRIPT_NAME'], 'PHP_SELF', and 'PATH_INFO' Mar 27, 2026
@henderkes henderkes marked this pull request as ready for review March 27, 2026 17:05
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)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm probably would be better to leave scriptName empty if the worker is in the public path:

root /some/path
worker /other/path {
  match *
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about that. Shouldn't it show /other/path/index.php then?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure either TBH. In CGI spec it's the path relative to the root, so /other/path/index.php might be misleading.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@henderkes henderkes changed the title fix $_SERVER['SCRIPT_NAME'], 'PHP_SELF', and 'PATH_INFO' fix: set $_SERVER variables: 'SCRIPT_NAME', 'PHP_SELF', and 'PATH_INFO' Mar 31, 2026
Co-authored-by: Marc <m@pyc.ac>
Signed-off-by: Marc <m@pyc.ac>
Copy link
Copy Markdown
Member

@dunglas dunglas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>";
Copy link
Copy Markdown
Member

@dunglas dunglas Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes to revert?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_SELF from SCRIPT_NAME + PATH_INFO, and update CGI path splitting logic for worker-assigned requests.
  • Update Caddy php_server rewrite/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.

henderkes and others added 2 commits April 8, 2026 21:00
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>
Copy link
Copy Markdown
Member

@alexandre-daubois alexandre-daubois left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just realized the same is true for documentUri (should be empty with match), probably makes sense to move the worker check before this block.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't even know that's a server variable. Will move the check up later.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

$_SERVER['SCRIPT_NAME'] is empty in worker mode

5 participants