A 5.6-era app I inherited had this line in composer.json:
"autoload": { "files": ["lib/helpers.php"] }
On PHP 7.4/FPM with include_path = ".:/var/www/shared/lib", require_once 'lib/helpers.php' silently loaded /var/www/shared/lib/helpers.php instead of the repo copy. The failure looked like a missing function until I checked get_included_files(). The root cause: relative paths hit include_path before the current working directory, and getcwd() in FPM is the script’s directory, not the project root.
My fix was to stop trusting relative requires and resolve through a single bootstrap constant:
// bootstrap.php
define('APP_ROOT', dirname(__DIR__));
require_once APP_ROOT . '/lib/helpers.php';
Then I audited every include, require, include_once, and require_once with a small script:
grep -rnE "(include|require)(_once)?\s*\(?\s*['\"]" --include='*.php' . \
| grep -vE "(dirname|__DIR__|APP_ROOT)"
Anything left was a candidate for the same bug. I also set include_path explicitly in the pool config rather than relying on the CLI default:
php_admin_value[include_path] = ".:/var/www/shared/lib"
Why this works: include_path is searched left to right, and . means the current working directory, which FPM sets per request. Absolute paths skip that search entirely, so the file you review is the file that runs. The trade-off is portability: hardcoding APP_ROOT means deployments must keep the same layout or define the constant from an environment value. __DIR__ is safer for files that may move, but it breaks when code is symlinked into a release directory, because __DIR__ resolves the symlink target. I hit that with Capistrano-style current symlinks, where __DIR__ pointed at the previous release.
Where it fails: CLI scripts and queue workers often have a different CWD and include_path than FPM, so a path that works in the browser can fail in artisan or a cron job. realpath_cache can also mask a moved file until the cache is cleared, which made one debugging session confusing. If you use open_basedir, absolute paths outside the allowed tree will fail loudly, which is usually better than silently loading the wrong file but still needs a config change.
The question: how do you detect a wrong-file include in CI before it reaches production, short of asserting get_included_files() on every request?


0 条评论
还没有评论,写下第一条。