PHP7提供了一种名为opcache的字节码缓存机制。我想知道是否有任何方法可以分发和运行" opcached" PHP脚本(.bin文件扩展名)的版本,不分发其源代码。 (我在opcache.file_cache
中启用了php.ini
指令以获取.bin文件。)
我假设在执行脚本时,PHP7会检查opcache目录中是否有匹配名称,时间戳的.bin文件,甚至可能比较校验和或哈希值。如果所有内容都匹配,PHP7将执行.bin文件而不是解析.php文件。也许有可能'欺骗'即使相应的.php脚本不存在,PHP也会执行.bin文件?
答案 0 :(得分:10)
PHP需要能够打开文件以便调用opcache;如果它不存在,则无法加载...
让我们look详细了解一下我们可能会玩的技巧:
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);
}
我们可以看到启用文件缓存的位置,它优先于共享内存缓存。
接下来,我们要查看file_cache_compile_file:
现在我们来看看zend_file_cache_script_load:
所以我们遇到的第一个问题是system id不是唯一的,而是由以下元素组成:
sizeof(char)
sizeof(int)
sizeof(long)
sizeof(size_t)
sizeof(zend_long)
ZEND_MM_ALIGNMENT
___DATE__
编译二进制日期___TIME___
二进制编译时间PHP版本和构建标识符是必需的,因为至少以下版本或构建版本之间可能会发生变化:
二进制标识符是必需的,因为至少zval的布局随着字节序和体系结构而变化:体系结构可能会影响一些基本编译器类型(long,size_t等)的大小以及上层和这些类型的下限,而endianess可以影响结构中成员的顺序,以及基本编译器类型的二进制表示。
请注意,要花费大量精力来识别当前系统,这应该会让你停下来思考......
禁用时间戳opcache.validate_timestamps=0
的验证将允许加载文件缓存条目,即使文件系统上的当前文件为空。
标头中包含的校验和仅用于验证文件的脚本部分(位于标头之后),它不(也不能)包含系统标识符或校验和本身写入的标头
因此,您可以通过更改缓存文件的header中的系统标识符以与目标计算机标识符相对应,欺骗PHP从另一台计算机加载缓存文件。
或许有趣,但作为部署软件的方法,绝对不是。
文件缓存不是用于此目的,从不同的体系结构和/或构建加载缓存会使PHP崩溃。