Можно ли распространять файлы в формате PHP7 без исходного кода?
PHP7 предлагает механизм кэширования байт-кода, называемый opcache. Я хотел бы знать, есть ли способ распространять и запускать "opcached" версию скрипта PHP (с расширением.bin), не распространяя его исходный код. (Я включил opcache.file_cache
директива в php.ini
чтобы получить файл.bin.)
Я предполагаю, что при выполнении сценария PHP7 проверит каталог opcache на наличие файла.bin с соответствующим именем, временной меткой и, возможно, даже сравнит контрольную сумму или значение хеша. Если все совпадает, PHP7 выполнит файл.bin вместо анализа файла.php. Может быть, можно "обмануть" PHP для выполнения файла.bin, даже если соответствующий скрипт.php отсутствует?
1 ответ
PHP должен быть в состоянии открыть файл для запуска opcache; Если он не существует, он не может быть загружен...
Давайте посмотрим подробно, чтобы увидеть, какие трюки мы могли бы сыграть:
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:
- открыть
- читать заголовок ( макет)
- проверить магию "OPCACHE"
- проверить системный идентификатор
- опционально проверить временную метку
- выполнить чтение из кэшированного файла
- проверить контрольную сумму
Итак, первая проблема, с которой мы столкнулись, заключается в том, что системный идентификатор не уникален, а состоит из следующих элементов:
- Версия PHP
- Zend Extension идентификатор сборки
- Двоичный идентификатор, содержит следующее:
sizeof(char)
sizeof(int)
sizeof(long)
sizeof(size_t)
sizeof(zend_long)
ZEND_MM_ALIGNMENT
- Если не используется dev-версия PHP (не выпущена, из git):
___DATE__
дата компиляции двоичного файла___TIME___
время компиляции двоичного файла
Требуется версия PHP и идентификатор сборки, потому что по крайней мере следующее может меняться между версиями или сборками:
- интегральные идентификаторы для кодов операций
- макет внутренних структур
- последовательность инструкций, которую ожидает VM (детали существующей структуры управления могут изменяться, например. foreach)
- оптимизации, выполняемые opcache (потому что предыдущие могут оказаться небезопасными)
Двоичный идентификатор необходим, потому что по крайней мере компоновка zval изменяется в зависимости от порядка байтов и архитектуры: архитектура может влиять на размер некоторых базовых типов компилятора (long, size_t и т. Д.), А также на верхний и нижний пределы этих типов, в то время как endianess может влиять на порядок членов в структуре, а также на двоичное представление основных типов компилятора.
Обратите внимание, что довольно много усилий затрачивается на то, чтобы определить текущую систему, что должно дать вам паузу для размышлений...
Отключение проверки временных меток opcache.validate_timestamps=0
разрешит загрузку записи файлового кэша, даже если текущий файл в файловой системе пуст.
Контрольная сумма, включенная в заголовок, предназначена только для проверки раздела скрипта файла (который идет после заголовка), она не включает (и не может включать) заголовок, в который записан системный идентификатор, или сама контрольная сумма.
Таким образом, вы можете обмануть PHP при загрузке кэшированного файла с другого компьютера, изменив системный идентификатор в заголовке кэшированного файла, чтобы он соответствовал идентификатору целевого компьютера.
Тебе следует?
Для забавы, возможно, но как метод развертывания вашего программного обеспечения, определенно нет.
Файловый кеш не предназначен для этой цели, загрузка кешей из разных архитектур и / или сборок приведет к сбою PHP.