aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe-php-rpc/php/worker.php
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-07-26 00:18:54 +0900
committernsfisis <nsfisis@gmail.com>2026-07-26 00:18:54 +0900
commited0da7fcc3056ce5a822ac0de63ccc2dc799006e (patch)
tree8689fb2797c3d9ced9b89a54753ad5d780c32cd5 /crates/shirabe-php-rpc/php/worker.php
parentf642329554cf18734e671dc4758bc045de489999 (diff)
downloadphp-shirabe-ed0da7fcc3056ce5a822ac0de63ccc2dc799006e.tar.gz
php-shirabe-ed0da7fcc3056ce5a822ac0de63ccc2dc799006e.tar.zst
php-shirabe-ed0da7fcc3056ce5a822ac0de63ccc2dc799006e.zip
feat(diagnose-command): query the real PHP runtime in one RPC call
diagnose used to read hardcoded shim stubs, so it described a fictional runtime: OPENSSL_VERSION_NUMBER was always 0 and tripped the TLSv1.1/1.2 check, PHP_BINARY and OPENSSL_VERSION_TEXT were empty, and the extension, function and ini probes answered from a fixed table. The PHP worker gained a `diagnose` entry that returns every fact the command needs as one PHP array, cached in a OnceLock so the several call sites share a single round trip. Reading it back needed array support in the serialize() parser, which in turn lets get_loaded_extensions and get_all_ini_files return real lists instead of comma-joined strings. Also fixes the openssl_version message, which dropped strstr()'s before_needle argument during the port, and check_connectivity's allow_url_fopen test, which did not follow PHP string truthiness. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe-php-rpc/php/worker.php')
-rw-r--r--crates/shirabe-php-rpc/php/worker.php95
1 files changed, 90 insertions, 5 deletions
diff --git a/crates/shirabe-php-rpc/php/worker.php b/crates/shirabe-php-rpc/php/worker.php
index 060373d5..1e5b726d 100644
--- a/crates/shirabe-php-rpc/php/worker.php
+++ b/crates/shirabe-php-rpc/php/worker.php
@@ -6,20 +6,53 @@ $client = @stream_socket_client('unix://' . $argv[1], $errno, $errstr);
if ($client === false) {
exit(1);
}
+// Port of Composer\XdebugHandler\XdebugHandler::setXdebugDetails(), which the diagnose payload
+// reports as `xdebug_active`.
+$xdebug_active = static function (): bool {
+ if (!extension_loaded('xdebug')) {
+ return false;
+ }
+
+ $version = phpversion('xdebug');
+ $version = $version !== false ? $version : 'unknown';
+
+ if (version_compare($version, '3.1', '>=')) {
+ $modes = xdebug_info('mode');
+ return (count($modes) === 0 ? 'off' : implode(',', $modes)) !== 'off';
+ }
+
+ $ini_mode = ini_get('xdebug.mode');
+ if ($ini_mode === false) {
+ return true;
+ }
+
+ $env_mode = (string) getenv('XDEBUG_MODE');
+ if ($env_mode !== '') {
+ $mode = $env_mode;
+ } else {
+ $mode = $ini_mode !== '' ? $ini_mode : 'off';
+ }
+
+ if (preg_match('/^,+$/', str_replace(' ', '', $mode)) === 1) {
+ $mode = 'off';
+ }
+
+ return $mode !== 'off';
+};
$dispatch = [
'defined' => static fn($name) => defined($name),
'constant' => static fn($name) => defined($name) ? constant($name) : null,
'inet_pton' => static fn($arg) => @inet_pton($arg),
'curl_version' => static fn($arg) => function_exists('curl_version') ? (curl_version()['version'] ?? null) : null,
'phpversion' => static fn($name) => phpversion($name),
- 'get_loaded_extensions' => static fn($arg) => implode(',', get_loaded_extensions()),
+ 'get_loaded_extensions' => static fn($arg) => get_loaded_extensions(),
'get_all_ini_files' => static function ($arg) {
$paths = [(string) php_ini_loaded_file()];
$scanned = php_ini_scanned_files();
if ($scanned !== false) {
$paths = array_merge($paths, array_map('trim', explode(',', $scanned)));
}
- return implode(',', $paths);
+ return $paths;
},
'extension_info' => static function ($name) {
if (!extension_loaded($name)) {
@@ -30,10 +63,62 @@ $dispatch = [
$re->info();
return (string) ob_get_clean();
},
- 'phpinfo' => static function ($what) {
+ 'diagnose' => static function ($arg) use ($xdebug_active) {
+ $extensions = [];
+ foreach ([
+ 'apcu',
+ 'curl',
+ 'filter',
+ 'hash',
+ 'iconv',
+ 'ionCube Loader',
+ 'mbstring',
+ 'openssl',
+ 'Phar',
+ 'uopz',
+ 'zip',
+ 'zlib',
+ ] as $extension) {
+ $extensions[$extension] = extension_loaded($extension);
+ }
+
+ $functions = [];
+ foreach (['disk_free_space', 'json_decode', 'proc_open'] as $function) {
+ $functions[$function] = function_exists($function);
+ }
+
+ $ini = [];
+ foreach ([
+ 'allow_url_fopen',
+ 'apc.enable_cli',
+ 'uopz.disable',
+ 'uopz.exit',
+ 'xdebug.profiler_enabled',
+ ] as $setting) {
+ $value = ini_get($setting);
+ $ini[$setting] = $value === false ? null : $value;
+ }
+
ob_start();
- phpinfo((int) $what);
- return (string) ob_get_clean();
+ phpinfo(INFO_GENERAL);
+ $phpinfo = (string) ob_get_clean();
+
+ return [
+ 'php_version' => PHP_VERSION,
+ 'php_version_id' => PHP_VERSION_ID,
+ 'php_binary' => defined('PHP_BINARY') ? PHP_BINARY : null,
+ 'openssl_version_text' => defined('OPENSSL_VERSION_TEXT') ? OPENSSL_VERSION_TEXT : null,
+ 'openssl_version_number' => defined('OPENSSL_VERSION_NUMBER') ? OPENSSL_VERSION_NUMBER : 0,
+ 'has_hhvm_version' => defined('HHVM_VERSION'),
+ 'has_php_windows_version_build' => defined('PHP_WINDOWS_VERSION_BUILD'),
+ 'xdebug_active' => $xdebug_active(),
+ 'ioncube_loader_iversion' => extension_loaded('ionCube Loader') ? ioncube_loader_iversion() : 0,
+ 'ioncube_loader_version' => extension_loaded('ionCube Loader') ? ioncube_loader_version() : '',
+ 'phpinfo_general' => $phpinfo,
+ 'extensions' => $extensions,
+ 'functions' => $functions,
+ 'ini' => $ini,
+ ];
},
];
$read_exact = static function ($conn, int $len): ?string {