PHP needs to be able to open the file for opcache to be invoked; If it doesn't exist, it can't be loaded ...
Let's look in detail, to see what tricks we might play:
if (!file_handle->filename || !ZCG(enabled) || !accel_startup_ok) {
/* The Accelerator is disabled, act as if without the Accelerator */
return accelerator_orig_compile_file(file_handle, type);
#ifdef HAVE_OPCACHE_FILE_CACHE
} else if (ZCG(accel_directives).file_cache_only) {
return file_cache_compile_file(file_handle, type);
#endif
} else if ((!ZCG(counted) && !ZCSG(accelerator_enabled)) ||
(ZCSG(restart_in_progress) && accel_restart_is_active())) {
#ifdef HAVE_OPCACHE_FILE_CACHE
if (ZCG(accel_directives).file_cache) {
return file_cache_compile_file(file_handle, type);
}
#endif
return accelerator_orig_compile_file(file_handle, type);
}
We can see that where the file cache is enabled, it takes precedence over the shared memory cache.
Next, we want to look at file_cache_compile_file:
- block signals
- protect shared memory
- zend_file_cache_script_load
Now we look at zend_file_cache_script_load:
- open
- read header (layout)
- verify magic "OPCACHE"
- verify system id
- optionally validate timestamp
- perform read of cached file
- verify checksum
So the first problem we have is that the system id is not unique, but is made up of the following elements:
- PHP version
- Zend Extension build identifier
- Binary identifier, contains the following:
sizeof(char)
sizeof(int)
sizeof(long)
sizeof(size_t)
sizeof(zend_long)
ZEND_MM_ALIGNMENT
- If not using a dev version of PHP (unreleased, from git):
___DATE__
compile date of binary
___TIME___
compile time of binary
The PHP version and build identifier are required because at least the following may change between versions or builds:
- integral identifiers for opcodes
- the layout of internal structures
- the sequence of instructions the VM expects (details of an existing control structure may change fe. foreach)
- optimizations performed by opcache (because previous ones may be discovered to be unsafe)
The binary identifier is required because at least the layout of a zval changes with endianess and architecture: Architecture may effect the size of some basic compiler types (long, size_t and so on) as well as the upper and lower limits of those types, while endianess can effect the order of members in the structure, as well as the binary representation of basic compiler types.
Note that rather a lot of effort is expended to identify the current system, that should give you pause for thought ...
Disabling validation of timestamps opcache.validate_timestamps=0
will allow the loading of a file cache entry, even if the current file on the file system is empty.
The checksum included in the header is only to verify the script section of the file (which comes after the header), it doesn't (and can't) include the header where the system identifier, or checksum itself is written.
So you can trick PHP into loading a cached file from another machine by changing the system identifier in the header of the cached file to correspond with the target machines identifier.
Should you ?
For fun perhaps, but as a method of deploying your software, definitely not.
The file cache is not intended for this purpose, loading caches from different architectures and or builds will crash PHP.