From 2a097a2ecf2cb362c179c1566ef2f8b7a45f0877 Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Mon, 1 Sep 2025 05:48:58 +0200 Subject: [PATCH] provide stable machine interface for ini on command line with json --- sapi/cli/cli.h | 1 + sapi/cli/php_cli.c | 54 +++++++++++++++++++++++++++++++++++++++++ sapi/cli/tests/026.phpt | 54 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+) create mode 100644 sapi/cli/tests/026.phpt diff --git a/sapi/cli/cli.h b/sapi/cli/cli.h index 85b55af3845d8..237f2516137f2 100644 --- a/sapi/cli/cli.h +++ b/sapi/cli/cli.h @@ -50,6 +50,7 @@ typedef enum php_cli_mode { PHP_CLI_MODE_REFLECTION_ZEND_EXTENSION = 12, PHP_CLI_MODE_SHOW_INI_CONFIG = 13, PHP_CLI_MODE_SHOW_INI_DIFF = 14, + PHP_CLI_MODE_SHOW_INI_JSON = 15, } php_cli_mode; typedef struct php_cli_server_context { diff --git a/sapi/cli/php_cli.c b/sapi/cli/php_cli.c index e212a0f71a23d..6179cae0c12ec 100644 --- a/sapi/cli/php_cli.c +++ b/sapi/cli/php_cli.c @@ -25,8 +25,10 @@ #include "zend_hash.h" #include "zend_modules.h" #include "zend_interfaces.h" +#include "zend_smart_str.h" #include "ext/reflection/php_reflection.h" +#include "ext/json/php_json.h" #include "SAPI.h" @@ -826,6 +828,8 @@ static int do_cli(int argc, char **argv) /* {{{ */ if (php_optarg) { if (strcmp(php_optarg, "diff") == 0) { context.mode = PHP_CLI_MODE_SHOW_INI_DIFF; + } else if(strcmp(php_optarg, "json") == 0) { + context.mode = PHP_CLI_MODE_SHOW_INI_JSON; } else { param_error = "Unknown argument for --ini\n"; } @@ -1148,6 +1152,56 @@ static int do_cli(int argc, char **argv) /* {{{ */ zend_array_destroy(sorted); break; } + case PHP_CLI_MODE_SHOW_INI_JSON: + { + zval out; + array_init_size(&out, 4); + + add_assoc_string(&out, "path", PHP_CONFIG_FILE_PATH); + if (php_ini_opened_path) { + add_assoc_string(&out, "file", php_ini_opened_path); + } + if (php_ini_scanned_path) { + add_assoc_string(&out, "scan", php_ini_scanned_path); + } + if (php_ini_scanned_files) { + char* scanning = estrdup(php_ini_scanned_files); + char* token; + char* next = php_strtok_r(scanning, ",\n", &token); + zval scanned; + array_init(&scanned); + + while (next) { + while (*next == ' ' || *next == '\t') { + next++; + } + if (*next != '\0') { + char *end = next + strlen(next) - 1; + while (end > next && (*end == ' ' || *end == '\t')) { + *end = '\0'; + end--; + } + add_next_index_string(&scanned, next); + } + next = php_strtok_r(NULL, ",\n", &token); + } + add_assoc_zval(&out, "scanned", &scanned); + efree(scanning); + } + smart_str buf = {0}; + if (php_json_encode(&buf, &out, + PHP_JSON_PRETTY_PRINT) == SUCCESS) { + fwrite(ZSTR_VAL(buf.s), 1, ZSTR_LEN(buf.s), stdout); + fwrite("\n", 1, sizeof("\n")-1, stdout); + } else { + fprintf(stderr, + "An error occured while trying to encode configuration\n"); + EG(exit_status) = 1; + } + smart_str_free(&buf); + zval_dtor(&out); + break; + } } } zend_end_try(); diff --git a/sapi/cli/tests/026.phpt b/sapi/cli/tests/026.phpt new file mode 100644 index 0000000000000..f2933e1f7e6fa --- /dev/null +++ b/sapi/cli/tests/026.phpt @@ -0,0 +1,54 @@ +--TEST-- +CLI php --ini=json +--SKIPIF-- + +--FILE-- + php_ini_loaded_file(), + \"scanned\" => php_ini_scanned_files() ?: []]);'", + $php)); + +$response["interface"] = \json_decode($interface, + JSON_THROW_ON_ERROR|JSON_OBJECT_AS_ARRAY); +$response["script"] = \json_decode($script, + JSON_THROW_ON_ERROR); +if (isset($response["script"]["scanned"]) && + $response["script"]["scanned"]) { + $response["script"]["scanned"] = + \array_map('trim',\explode( + ",\n", $response["script"]["scanned"])); +} + +if (!isset($response["interface"]["file"]) && + isset($response["script"]["file"]) && + $response["script"]["file"]) { + echo "interface is missing file\n"; + var_dump($response); +} + +if (!isset($response["interface"]["scanned"]) && + isset($response["script"]["scanned"]) && + $response["script"]["scanned"]) { + echo "interface is missing scanned\n"; + var_dump($response); +} + +if (isset($response["interface"]["scanned"]) && + $response["interface"]["scanned"] != $response["script"]["scanned"]) { + echo "interface and script scanned do not match\n"; + var_dump($response); +} + +echo "OK\n"; +?> +--EXPECT-- +OK \ No newline at end of file