[php-src] Issue #15246: PHP-FPM + Apache: special characters in SCRIPT_FILENAME are URL encoded

From: Date: Mon, 05 Aug 2024 10:47:32 +0000
Subject: [php-src] Issue #15246: PHP-FPM + Apache: special characters in SCRIPT_FILENAME are URL encoded
Groups: php.bugs 
Request: Send a blank email to php-bugs+get-247435@lists.php.net to get a copy of this message
Issue: https://github.com/php/php-src/issues/15246 Author: abgandar ### Description ### Problem I use Apache + PHP-FPM to serve PHP files sitting in the server's document root. Some PHP files have spaces and UTF-8 encoded special characters (umlauts, accents) in their file names. Files without spaces or umlauts are served correctly, but files with any of those lead to a 404 with PHP-FPM responding 'Primary script unknown'. This appears to be due to the way Apache passes the SCRIPT_FILENAME variable: it seems to prefix the physical file name by proxy:fcgi:// and then URL encodes the file name following. So the correctly resolved file name "/docroot/my file.php" gets passed as "proxy:fcgi://docroot/my%20file.php". PHP-FPM removes the prefix, but then tries to find the file "/docroot/my%20file.php", which doesn't exist. This seems to me to be related to #12996: the fix to that bug was to URL decode PATH_INFO, but it does not cover the case where the physical script file (SCRIPT_FILENAME) is also URL encoded. So it just URL decodes the bit after the file name. ### Symptoms Using the following PHP-FPM access log format ``` access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{ORIG_SCRIPT_FILENAME}e" ``` when requesting the URL ``` https://my.server/files/test%20me.php ``` I get logs like this ``` - - 04/Aug/2024:21:35:48 +0200 "GET /files/test me.php" 404 - /var/htdocs/files/test%20me.php ``` Note the request (%r) is URL decoded, but the ORIG_SCRIPT_FILENAME is not. The file "/var/htdocs/files/test me.php" exists and is readable by the php-fpm user. Files without the space work fine. I use ORIG_SCRIPT_FILENAME because PHP-FPM unsets SCRIPT_FILENAME when reporting a 404 error (hence the empty %f), but saves the value in ORIG_SCRIPT_FILENAME. ### Setup I'm using PHP 8.3.10 with Apache/2.4.62 (FreeBSD) OpenSSL/3.2.2 on FreeBSD 14.1-STABLE (both built from ports). Relevant Apache config: ``` <FilesMatch "\.php$"> SetHandler "proxy:unix:/var/run/php-fpm.sock|fcgi://php-fpm" </FilesMatch> <Proxy "fcgi://php-fpm" enablereuse=off max=18> </Proxy> # PHP Apache FCGI hack to pass HTTP AUTH info ProxyFCGISetEnvIf "%{HTTP:Authorization} =~ /(.+)/" HTTP_AUTHORIZATION "$1" ProxyFCGISetEnvIf "%{REMOTE_USER} =~ /(.+)/" PHP_AUTH_USER "$1" ``` My PHP-FPM setup is stock with UNIX socket at /var/run/php-fpm.sock and access logging as per above. I have had this setup unchanged for several years and PHP and Apache versions. I'm pretty sure this worked about half a year ago, but can't say when precisely this broke (and if it was a change on the Apache or PHP side). ### Workaround As a workaround, I can make everything run just fine by forcing Apache to unescape the SCRIPT_FILENAME variable before passing it to PHP-FPM: ``` ProxyFCGISetEnvIf "true" SCRIPT_FILENAME "%{unescape:%{SCRIPT_FILENAME}}" ``` I don't know what that does to PATH_INFO stuff as I don't use that. ### Solution(?) Since fpm_main.c already does a lot of gymnastics to fix Apache's botched inputs, it may be better to unescape the SCRIPT_FILENAME when removing the "proxy:fcgi://" prefix in [fpm_main.c](https://github.com/php/php-src/blob/50217b35ea678b585b26e4edf30844f198017b22/sapi/fpm/fpm/fpm_main.c#L1018C35-L1018C48). Unfortunately, I don't fully understand all the logic there, and am not familiar enough with PHP sources to confidently propose a fix. ### PHP Version PHP 8.3.10 ### Operating System FreeBSD 14.1-STABLE

« previous php.bugs (#247435) next »