diff --git a/src/SPC/command/BuildCliCommand.php b/src/SPC/command/BuildCliCommand.php index 298c0aa9..b6cf3461 100644 --- a/src/SPC/command/BuildCliCommand.php +++ b/src/SPC/command/BuildCliCommand.php @@ -7,6 +7,7 @@ namespace SPC\command; use SPC\builder\BuilderProvider; use SPC\exception\ExceptionHandler; use SPC\exception\WrongUsageException; +use SPC\store\SourcePatcher; use SPC\util\DependencyUtil; use SPC\util\LicenseDumper; use Symfony\Component\Console\Attribute\AsCommand; @@ -27,6 +28,7 @@ class BuildCliCommand extends BuildCommand $this->addOption('build-all', null, null, 'build cli, micro, fpm'); $this->addOption('no-strip', null, null, 'build without strip, in order to debug and load external extensions'); $this->addOption('enable-zts', null, null, 'enable ZTS support'); + $this->addOption('with-hardcoded-ini', 'I', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Patch PHP source code, inject hardcoded INI'); } public function handle(): int @@ -72,6 +74,16 @@ class BuildCliCommand extends BuildCommand $builder->proveExts($extensions); // strip $builder->setStrip(!$this->getOption('no-strip')); + // Process -I option + $custom_ini = []; + foreach ($this->input->getOption('with-hardcoded-ini') as $value) { + [$source_name, $ini_value] = explode('=', $value, 2); + $custom_ini[$source_name] = $ini_value; + logger()->info('Adding hardcoded INI [' . $source_name . ' = ' . $ini_value . ']'); + } + if (!empty($custom_ini)) { + SourcePatcher::patchHardcodedINI($custom_ini); + } // 构建 $builder->buildPHP($rule, $this->getOption('bloat')); // 统计时间 diff --git a/src/SPC/store/SourcePatcher.php b/src/SPC/store/SourcePatcher.php index c15a83b2..4bcc8d31 100644 --- a/src/SPC/store/SourcePatcher.php +++ b/src/SPC/store/SourcePatcher.php @@ -146,4 +146,56 @@ class SourcePatcher } } } + + /** + * @throws FileSystemException + */ + public static function patchHardcodedINI(array $ini = []): bool + { + $cli_c = SOURCE_PATH . '/php-src/sapi/cli/php_cli.c'; + $cli_c_bak = SOURCE_PATH . '/php-src/sapi/cli/php_cli.c.bak'; + $micro_c = SOURCE_PATH . '/php-src/sapi/micro/php_micro.c'; + $micro_c_bak = SOURCE_PATH . '/php-src/sapi/micro/php_micro.c.bak'; + + // Try to reverse backup file + $find_pattern = 'const char HARDCODED_INI[] ='; + $patch_str = ''; + foreach ($ini as $key => $value) { + $patch_str .= "\"{$key}={$value}\\n\"\n"; + } + $patch_str = "const char HARDCODED_INI[] =\n{$patch_str}"; + + // Detect backup, if we have backup, it means we need to reverse first + if (file_exists($cli_c_bak) || file_exists($micro_c_bak)) { + self::unpatchHardcodedINI(); + } + + // Backup it + $result = file_put_contents($cli_c_bak, file_get_contents($cli_c)); + $result = $result && file_put_contents($micro_c_bak, file_get_contents($micro_c)); + if ($result === false) { + return false; + } + + // Patch it + FileSystem::replaceFile($cli_c, REPLACE_FILE_STR, $find_pattern, $patch_str); + FileSystem::replaceFile($micro_c, REPLACE_FILE_STR, $find_pattern, $patch_str); + return true; + } + + public static function unpatchHardcodedINI(): bool + { + $cli_c = SOURCE_PATH . '/php-src/sapi/cli/php_cli.c'; + $cli_c_bak = SOURCE_PATH . '/php-src/sapi/cli/php_cli.c.bak'; + $micro_c = SOURCE_PATH . '/php-src/sapi/micro/php_micro.c'; + $micro_c_bak = SOURCE_PATH . '/php-src/sapi/micro/php_micro.c.bak'; + if (!file_exists($cli_c_bak) && !file_exists($micro_c_bak)) { + return false; + } + $result = file_put_contents($cli_c, file_get_contents($cli_c_bak)); + $result = $result && file_put_contents($micro_c, file_get_contents($micro_c_bak)); + @unlink($cli_c_bak); + @unlink($micro_c_bak); + return $result; + } }