From 548463bad1f72c97f68b47f54a263a4f4ad87b3a Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sat, 15 Aug 2026 07:37:45 +0900 Subject: feat(php-rpc): embed the Composer PHP runtime in the executable Plugins and scripts need the real `Composer\` classes and the packages Composer depends on, which so far came from a checkout found through SHIRABE_COMPOSER_PHP_DIR or a path next to the workspace. Neither exists for a distributed binary. The build script now archives those PHP sources into a phar the way Compiler.php does and the executable carries it. The worker maps it with Phar::loadPhar and reads a content-addressed sentinel back to tell a bundle it can use from one it cannot; where its PHP cannot open the phar, the bundle is unpacked once into the cache directory and autoloaded from there. SHIRABE_COMPOSER_PHP_DIR still overrides both for development. PHP locates a phar's manifest by the first __HALT_COMPILER(); token in the file, so the executable must hold no other copy of it: phar.rs builds the token at run time, and a linter keeps further literals out of the sources that reach the binary. Co-Authored-By: Claude Opus 5 (1M context) --- crates/shirabe-php-rpc/php/worker.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'crates/shirabe-php-rpc/php/worker.php') diff --git a/crates/shirabe-php-rpc/php/worker.php b/crates/shirabe-php-rpc/php/worker.php index 5946a52f..d5fe67d4 100644 --- a/crates/shirabe-php-rpc/php/worker.php +++ b/crates/shirabe-php-rpc/php/worker.php @@ -716,6 +716,26 @@ ShirabeRpcRuntime::$dispatch = [ ShirabeRpcRuntime::ensureStubAutoloaderPriority(); return true; }, + // Tries to open the embedded runtime bundle and maps the phar to $alias. + // Returns whether the extraction succeeds or not. + '__shirabe_open_runtime_bundle' => static function ($args) { + [$executable, $alias, $sentinel, $bundleId] = $args; + if (!extension_loaded('phar') || !in_array('phar', stream_get_wrappers(), true)) { + return false; + } + try { + Phar::loadPhar($executable, $alias); + $read = @file_get_contents("phar://{$alias}/{$sentinel}"); + } catch (Throwable $e) { + $read = false; + } + // The phar bundle is unsigned, so the worker process is started with + // phar.require_hash=0. Verification result is saved and not verified + // again for the same phar file, so it is safe to restore the settings + // here. + ini_set('phar.require_hash', '1'); + return $read === $bundleId; + }, '__shirabe_enable_script_autoloader' => static function ($args) { ShirabeRpcRuntime::enableScriptAutoloader(); return true; -- cgit v1.3.1-4-g156e