Add opcache_is_script_cached_in_file_cache() function

Closes GH-16979
This commit is contained in:
Samuel Melrose 2025-07-16 17:24:11 +02:00 committed by Ilija Tovilo
parent b9844b545f
commit 6f1501a601
No known key found for this signature in database
GPG key ID: 5050C66BFCD1015A
8 changed files with 121 additions and 1 deletions

View file

@ -430,6 +430,9 @@ PHP 8.5 UPGRADE NOTES
. Added grapheme_levenshtein() function.
RFC: https://wiki.php.net/rfc/grapheme_levenshtein
- Opcache:
. Added opcache_is_script_cached_in_file_cache().
- Pdo\Sqlite:
. Added support for Pdo\Sqlite::setAuthorizer(), which is the equivalent of
SQLite3::setAuthorizer(). The only interface difference is that the

View file

@ -23,3 +23,5 @@ function opcache_jit_blacklist(Closure $closure): void {}
function opcache_get_configuration(): array|false {}
function opcache_is_script_cached(string $filename): bool {}
function opcache_is_script_cached_in_file_cache(string $filename): bool {}

View file

@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: c416c231c5d1270b7e5961f84cc3ca3e29db4959 */
* Stub hash: a8de025fa96a78db3a26d53a18bb2b365d094eca */
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_opcache_reset, 0, 0, _IS_BOOL, 0)
ZEND_END_ARG_INFO()
@ -26,6 +26,8 @@ ZEND_END_ARG_INFO()
#define arginfo_opcache_is_script_cached arginfo_opcache_compile_file
#define arginfo_opcache_is_script_cached_in_file_cache arginfo_opcache_compile_file
ZEND_FUNCTION(opcache_reset);
ZEND_FUNCTION(opcache_get_status);
ZEND_FUNCTION(opcache_compile_file);
@ -33,6 +35,7 @@ ZEND_FUNCTION(opcache_invalidate);
ZEND_FUNCTION(opcache_jit_blacklist);
ZEND_FUNCTION(opcache_get_configuration);
ZEND_FUNCTION(opcache_is_script_cached);
ZEND_FUNCTION(opcache_is_script_cached_in_file_cache);
static const zend_function_entry ext_functions[] = {
ZEND_FE(opcache_reset, arginfo_opcache_reset)
@ -42,5 +45,6 @@ static const zend_function_entry ext_functions[] = {
ZEND_FE(opcache_jit_blacklist, arginfo_opcache_jit_blacklist)
ZEND_FE(opcache_get_configuration, arginfo_opcache_get_configuration)
ZEND_FE(opcache_is_script_cached, arginfo_opcache_is_script_cached)
ZEND_FE(opcache_is_script_cached_in_file_cache, arginfo_opcache_is_script_cached_in_file_cache)
ZEND_FE_END
};

View file

@ -0,0 +1,3 @@
<?php
function test() {}

View file

@ -0,0 +1,48 @@
--TEST--
GH-16979: Test opcache_is_script_cached_in_file_cache function
--SKIPIF--
<?php
@mkdir(__DIR__ . '/gh16979_cache', 0777, true);
?>
--INI--
opcache.enable=1
opcache.enable_cli=1
opcache.jit=disable
opcache.file_cache="{PWD}/gh16979_cache"
opcache.file_update_protection=0
--EXTENSIONS--
opcache
--FILE--
<?php
$file = __DIR__ . '/gh16979_check_file_cache_function.inc';
var_dump(opcache_is_script_cached_in_file_cache($file));
opcache_compile_file($file);
var_dump(opcache_is_script_cached_in_file_cache($file));
opcache_invalidate($file, force: true);
var_dump(opcache_is_script_cached_in_file_cache($file));
?>
--CLEAN--
<?php
function removeDirRecursive($dir) {
if (!is_dir($dir)) return;
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
RecursiveIteratorIterator::CHILD_FIRST
);
foreach ($iterator as $fileinfo) {
if ($fileinfo->isDir()) {
@rmdir($fileinfo->getRealPath());
} else {
@unlink($fileinfo->getRealPath());
}
}
@rmdir($dir);
}
removeDirRecursive(__DIR__ . '/gh16979_cache');
?>
--EXPECT--
bool(false)
bool(true)
bool(false)

View file

@ -27,6 +27,7 @@
#include "zend_closures.h"
#include "zend_shared_alloc.h"
#include "zend_accelerator_blacklist.h"
#include "zend_file_cache.h"
#include "php_ini.h"
#include "SAPI.h"
#include "zend_virtual_cwd.h"
@ -364,6 +365,23 @@ static int filename_is_in_cache(zend_string *filename)
return 0;
}
static int filename_is_in_file_cache(zend_string *filename)
{
zend_string *realpath = zend_resolve_path(filename);
if (!realpath) {
return 0;
}
zend_file_handle handle;
zend_stream_init_filename_ex(&handle, filename);
handle.opened_path = realpath;
zend_persistent_script *result = zend_file_cache_script_load_ex(&handle, true);
zend_destroy_file_handle(&handle);
return result != NULL;
}
static int accel_file_in_cache(INTERNAL_FUNCTION_PARAMETERS)
{
if (ZEND_NUM_ARGS() == 1) {
@ -999,3 +1017,27 @@ ZEND_FUNCTION(opcache_is_script_cached)
RETURN_BOOL(filename_is_in_cache(script_name));
}
/* {{{ Return true if the script is cached in OPCache file cache, false if it is not cached or if OPCache is not running. */
ZEND_FUNCTION(opcache_is_script_cached_in_file_cache)
{
zend_string *script_name;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_STR(script_name)
ZEND_PARSE_PARAMETERS_END();
if (!validate_api_restriction()) {
RETURN_FALSE;
}
if (!(ZCG(accelerator_enabled) || ZCG(accel_directives).file_cache_only)) {
RETURN_FALSE;
}
if (!ZCG(accel_directives).file_cache) {
RETURN_FALSE;
}
RETURN_BOOL(filename_is_in_file_cache(script_name));
}

View file

@ -1871,7 +1871,14 @@ static void zend_file_cache_unserialize(zend_persistent_script *script,
zend_file_cache_unserialize_early_bindings(script, buf);
}
static zend_persistent_script file_cache_validate_success_script;
zend_persistent_script *zend_file_cache_script_load(zend_file_handle *file_handle)
{
return zend_file_cache_script_load_ex(file_handle, false);
}
zend_persistent_script *zend_file_cache_script_load_ex(zend_file_handle *file_handle, bool validate_only)
{
zend_string *full_path = file_handle->opened_path;
int fd;
@ -1948,6 +1955,16 @@ zend_persistent_script *zend_file_cache_script_load(zend_file_handle *file_handl
return NULL;
}
/* return here if validating */
if (validate_only) {
if (zend_file_cache_flock(fd, LOCK_UN) != 0) {
zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot unlock file '%s'\n", filename);
}
close(fd);
efree(filename);
return &file_cache_validate_success_script;
}
checkpoint = zend_arena_checkpoint(CG(arena));
#if defined(__AVX__) || defined(__SSE2__)
/* Align to 64-byte boundary */

View file

@ -21,6 +21,7 @@
int zend_file_cache_script_store(zend_persistent_script *script, bool in_shm);
zend_persistent_script *zend_file_cache_script_load(zend_file_handle *file_handle);
zend_persistent_script *zend_file_cache_script_load_ex(zend_file_handle *file_handle, bool validate_only);
void zend_file_cache_invalidate(zend_string *full_path);
#endif /* ZEND_FILE_CACHE_H */