PHP7 offers a bytecode caching mechanism called opcache. I'd like to know if there is any way to distribute and run the "opcached" version of a PHP script (.bin file extension) without distributing its source code. (I enabled the opcache.file_cache
directive in php.ini
to obtain the .bin file.)
I assume that when executing a script, PHP7 will check the opcache directory for a .bin file with matching name, timestamp, and maybe even compare a checksum or hash value. If all things match, PHP7 will execute the .bin file instead of parse the .php file. Maybe it is possible to 'trick' PHP into executing the .bin file even when the corresponding .php script is not present?
OPcache is a caching engine built into PHP. When enabled, it dramatically increases the performance of websites that utilize PHP. From php.net: OPcache improves PHP performance by storing precompiled script bytecode in shared memory, thereby removing the need for PHP to load and parse scripts on each request.
To flush PHP Opcache on the PHP-FPM method, you have to send a reload to your PHP-FPM daemon. The reload will clear the Opcache, and when the next request arrives, it will force it to rebuild the cache. You can flush the entire cache of all the websites by reloading the single master.
Show activity on this post. Zend Server, a commercial product developed by the Zend Corporation (since aquired by RougeWave) have a feature called OPCache. Stand alone open source PHP also has a feature called OPcache, available since PHP 5.5.
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:
Now we look at zend_file_cache_script_load:
So the first problem we have is that the system id is not unique, but is made up of the following elements:
sizeof(char)
sizeof(int)
sizeof(long)
sizeof(size_t)
sizeof(zend_long)
ZEND_MM_ALIGNMENT
___DATE__
compile date of binary___TIME___
compile time of binaryThe PHP version and build identifier are required because at least the following may change between versions or builds:
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With