Skip to content

Fix GH-13989: Allow opcache.file_cache_only=1 without source files#21236

Open
pronskiy wants to merge 1 commit intophp:masterfrom
pronskiy:fix/gh-13989-file-cache-only-no-source
Open

Fix GH-13989: Allow opcache.file_cache_only=1 without source files#21236
pronskiy wants to merge 1 commit intophp:masterfrom
pronskiy:fix/gh-13989-file-cache-only-no-source

Conversation

@pronskiy
Copy link
Member

@pronskiy pronskiy commented Feb 16, 2026

When opcache.file_cache_only=1 is enabled and the file cache is warm, PHP currently requires source files to exist on disk even though it serves compiled opcodes from cache. This prevents legitimate deployment workflows where source code is stripped from the final image (e.g., Docker, PHAR, WASM).

This PR makes PHP fall back to the file cache when source files are missing, instead of failing with "Could not open input file" or "Failed opening required".

Changes

sapi/cli/php_cli.c -- When opcache.file_cache_only=1 is set and the script file doesn't exist, defer to opcache instead of immediately failing. The original "Could not open input file" error is preserved when opcache is not involved.
ext/opcache/ZendAccelerator.c -- Two changes:

  • file_cache_compile_file(): Try loading from file cache before attempting to open the source file. Paths are canonicalized via expand_filepath_with_mode(CWD_EXPAND) so that ./foo.php, bar/../foo.php, and /app/foo.php all resolve to the same cache entry.
  • persistent_zend_resolve_path(): In file_cache_only mode, when the original resolver fails (file missing), return the canonicalized path so the file cache can look it up.

ext/opcache/zend_file_cache.c -- When validate_timestamps=1 and the source file is missing (timestamp 0), serve from cache instead of invalidating it.

Limitations

  • CLI only for the primary script. FPM/CGI SAPIs check file existence before opcache can intercept, so the entry point script must still exist on disk (can be empty). Included/required files work in all SAPIs.
  • Requires absolute paths or CWD-resolvable paths. Include-path-based resolution needs the source file for initial path discovery. Composer classmap autoloaders (which use absolute paths) work fully.

Test plan

  • gh13989_file_cache_only_no_source — basic include from cache after source deletion
  • gh13989_file_cache_only_no_source_require — same with require
  • gh13989_file_cache_only_cli_primary — CLI primary script from cache
  • gh13989_file_cache_only_autoload — Composer-style classmap autoloading
  • gh13989_file_cache_only_phar — PHAR with stripped source
  • gh13989_file_cache_only_validate_timestamps — validate_timestamps=1 with missing source
  • gh13989_file_cache_only_relative_path — ./ and ../ path canonicalization
  • gh13989_file_cache_only_cli_missing_no_cache — preserves "Could not open input file" without opcache
  • gh13989_file_cache_only_docker — end-to-end Docker deployment scenario (Linux only)

Closes GH-13989.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PHP checks the filesystem for file existing even if available in opcache and all opcache validations are disabled

1 participant