From d5cebf4ba8ac1e477a4398e05ea413e28d12f11b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Thu, 19 May 2022 14:00:06 +0200 Subject: [PATCH 1/8] feat: add CLI support --- frankenphp.c | 16 ++++++++++++++++ frankenphp.go | 19 +++++++++++++++++++ frankenphp.h | 2 ++ frankenphp_test.go | 6 ++++++ testdata/command.php | 3 +++ 5 files changed, 46 insertions(+) create mode 100644 testdata/command.php diff --git a/frankenphp.c b/frankenphp.c index 20f51fee4..e279db166 100644 --- a/frankenphp.c +++ b/frankenphp.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -663,3 +664,18 @@ int frankenphp_execute_script(const char* file_name) return status; } + +int frankenphp_execute_script_cli(char *script, int argc, char **argv) { + int status; + + PHP_EMBED_START_BLOCK(argc, argv) + + zend_file_handle file_handle; + zend_stream_init_filename(&file_handle, script); + + status = php_execute_script(&file_handle); + + PHP_EMBED_END_BLOCK() + + return status; +} diff --git a/frankenphp.go b/frankenphp.go index 04bfeba18..0e5c79c4f 100644 --- a/frankenphp.go +++ b/frankenphp.go @@ -666,3 +666,22 @@ func go_log(message *C.char, level C.int) { l.Info(m, zap.Stringer("syslog_level", syslogLevel(level))) } } + +func ExecuteScriptCLI(script string, args []string) error { + cScript := C.CString(script) + defer C.free(unsafe.Pointer(cScript)) + + argc := C.int(len(args)) + argv := make([]*C.char, argc) + for i, arg := range args { + argv[i] = C.CString(arg) + } + + runtime.LockOSThread() + + if C.frankenphp_execute_script_cli(cScript, argc, (**C.char)(unsafe.Pointer(&argv[0]))) == -1 { + return fmt.Errorf("error exuction script %s", script) + } + + return nil +} diff --git a/frankenphp.h b/frankenphp.h index 3e85e287b..64e854134 100644 --- a/frankenphp.h +++ b/frankenphp.h @@ -53,4 +53,6 @@ int frankenphp_execute_script(const char *file_name); uintptr_t frankenphp_request_shutdown(); void frankenphp_register_bulk_variables(char **variables, size_t size, zval *track_vars_array); +int frankenphp_execute_script_cli(char *script, int argc, char **argv); + #endif diff --git a/frankenphp_test.go b/frankenphp_test.go index eb4b50bb6..0e182439e 100644 --- a/frankenphp_test.go +++ b/frankenphp_test.go @@ -588,3 +588,9 @@ func testFiberNoCgo(t *testing.T, opts *testOptions) { assert.Equal(t, string(body), fmt.Sprintf("Fiber %d", i)) }, opts) } + +func TestExecuteScriptCLI(t *testing.T) { + cwd, _ := os.Getwd() + + assert.Nil(t, frankenphp.ExecuteScriptCLI(cwd+"/testdata/command.php", []string{"foo", "bar"})) +} diff --git a/testdata/command.php b/testdata/command.php new file mode 100644 index 000000000..65b3aa64f --- /dev/null +++ b/testdata/command.php @@ -0,0 +1,3 @@ + Date: Wed, 4 Oct 2023 12:08:33 +0200 Subject: [PATCH 2/8] updated --- .gitignore | 1 + frankenphp.c | 23 +++++++--- frankenphp.go | 12 ++--- frankenphp_test.go | 95 +++++++++++++++++++++++----------------- internal/testcli/main.go | 17 +++++++ testdata/command.php | 3 ++ 6 files changed, 97 insertions(+), 54 deletions(-) create mode 100644 internal/testcli/main.go diff --git a/.gitignore b/.gitignore index d7a674278..82e22c67b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ /caddy/frankenphp/frankenphp /internal/testserver/testserver +internal/testcli/testcli .idea/ .vscode/ __debug_bin diff --git a/frankenphp.c b/frankenphp.c index e279db166..102e3ac64 100644 --- a/frankenphp.c +++ b/frankenphp.c @@ -666,16 +666,25 @@ int frankenphp_execute_script(const char* file_name) } int frankenphp_execute_script_cli(char *script, int argc, char **argv) { - int status; + if (fork() == 0) { + return SUCCESS; + } - PHP_EMBED_START_BLOCK(argc, argv) + int exit_status; - zend_file_handle file_handle; - zend_stream_init_filename(&file_handle, script); + php_embed_module.pretty_name = "PHP CLI embedded in FrankenPHP"; - status = php_execute_script(&file_handle); + php_embed_init(argc, argv); + zend_first_try { + zend_file_handle file_handle; + zend_stream_init_filename(&file_handle, script); - PHP_EMBED_END_BLOCK() + php_execute_script(&file_handle); + } zend_end_try(); - return status; + exit_status = EG(exit_status); + + php_embed_shutdown(); + + return exit_status; } diff --git a/frankenphp.go b/frankenphp.go index 0e5c79c4f..6b8e5e058 100644 --- a/frankenphp.go +++ b/frankenphp.go @@ -667,7 +667,9 @@ func go_log(message *C.char, level C.int) { } } -func ExecuteScriptCLI(script string, args []string) error { +// ExecuteScriptCLI executes the PHP script passed as parameter. +// It returns the exit status code of the script. +func ExecuteScriptCLI(script string, args []string) int { cScript := C.CString(script) defer C.free(unsafe.Pointer(cScript)) @@ -677,11 +679,5 @@ func ExecuteScriptCLI(script string, args []string) error { argv[i] = C.CString(arg) } - runtime.LockOSThread() - - if C.frankenphp_execute_script_cli(cScript, argc, (**C.char)(unsafe.Pointer(&argv[0]))) == -1 { - return fmt.Errorf("error exuction script %s", script) - } - - return nil + return int(C.frankenphp_execute_script_cli(cScript, argc, (**C.char)(unsafe.Pointer(&argv[0])))) } diff --git a/frankenphp_test.go b/frankenphp_test.go index 0e182439e..05e9b69e5 100644 --- a/frankenphp_test.go +++ b/frankenphp_test.go @@ -12,6 +12,7 @@ import ( "net/textproto" "net/url" "os" + "os/exec" "strconv" "strings" "sync" @@ -85,29 +86,6 @@ func runTest(t *testing.T, test func(func(http.ResponseWriter, *http.Request), * wg.Wait() } -func BenchmarkHelloWorld(b *testing.B) { - if err := frankenphp.Init(frankenphp.WithLogger(zap.NewNop())); err != nil { - panic(err) - } - defer frankenphp.Shutdown() - cwd, _ := os.Getwd() - testDataDir := cwd + "/testdata/" - - handler := func(w http.ResponseWriter, r *http.Request) { - req := frankenphp.NewRequestWithContext(r, testDataDir, nil) - if err := frankenphp.ServeHTTP(w, req); err != nil { - panic(err) - } - } - - req := httptest.NewRequest("GET", "http://example.com/index.php", nil) - w := httptest.NewRecorder() - - for i := 0; i < b.N; i++ { - handler(w, req) - } -} - func TestHelloWorld_module(t *testing.T) { testHelloWorld(t, nil) } func TestHelloWorld_worker(t *testing.T) { testHelloWorld(t, &testOptions{workerScript: "index.php"}) @@ -557,21 +535,6 @@ func TestVersion(t *testing.T) { assert.NotEmpty(t, v.Version, 0) } -func ExampleServeHTTP() { - if err := frankenphp.Init(); err != nil { - panic(err) - } - defer frankenphp.Shutdown() - - http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - req := frankenphp.NewRequestWithContext(r, "/path/to/document/root", nil) - if err := frankenphp.ServeHTTP(w, req); err != nil { - panic(err) - } - }) - log.Fatal(http.ListenAndServe(":8080", nil)) -} - func TestFiberNoCgo_module(t *testing.T) { testFiberNoCgo(t, &testOptions{}) } func TestFiberNonCgo_worker(t *testing.T) { testFiberNoCgo(t, &testOptions{workerScript: "fiber-no-cgo.php"}) @@ -590,7 +553,61 @@ func testFiberNoCgo(t *testing.T, opts *testOptions) { } func TestExecuteScriptCLI(t *testing.T) { + cmd := exec.Command("go", "run", "internal/testcli/main.go", "testdata/command.php", "foo", "bar") + stdoutStderr, err := cmd.CombinedOutput() + assert.Error(t, err) + + stdoutStderrStr := string(stdoutStderr) + + assert.Contains(t, stdoutStderrStr, `"foo"`) + assert.Contains(t, stdoutStderrStr, `"bar"`) + assert.Contains(t, stdoutStderrStr, "From the CLI") + assert.Contains(t, stdoutStderrStr, "exit status 3") +} + +func ExampleServeHTTP() { + if err := frankenphp.Init(); err != nil { + panic(err) + } + defer frankenphp.Shutdown() + + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + req := frankenphp.NewRequestWithContext(r, "/path/to/document/root", nil) + if err := frankenphp.ServeHTTP(w, req); err != nil { + panic(err) + } + }) + log.Fatal(http.ListenAndServe(":8080", nil)) +} + +func ExampleExecuteScriptCLI() { + if len(os.Args) <= 1 { + log.Println("Usage: my-program script.php") + os.Exit(1) + } + + os.Exit(frankenphp.ExecuteScriptCLI(os.Args[1], os.Args)) +} + +func BenchmarkHelloWorld(b *testing.B) { + if err := frankenphp.Init(frankenphp.WithLogger(zap.NewNop())); err != nil { + panic(err) + } + defer frankenphp.Shutdown() cwd, _ := os.Getwd() + testDataDir := cwd + "/testdata/" + + handler := func(w http.ResponseWriter, r *http.Request) { + req := frankenphp.NewRequestWithContext(r, testDataDir, nil) + if err := frankenphp.ServeHTTP(w, req); err != nil { + panic(err) + } + } + + req := httptest.NewRequest("GET", "http://example.com/index.php", nil) + w := httptest.NewRecorder() - assert.Nil(t, frankenphp.ExecuteScriptCLI(cwd+"/testdata/command.php", []string{"foo", "bar"})) + for i := 0; i < b.N; i++ { + handler(w, req) + } } diff --git a/internal/testcli/main.go b/internal/testcli/main.go new file mode 100644 index 000000000..47a4ca186 --- /dev/null +++ b/internal/testcli/main.go @@ -0,0 +1,17 @@ +package main + +import ( + "log" + "os" + + "github.com/dunglas/frankenphp" +) + +func main() { + if len(os.Args) <= 1 { + log.Println("Usage: testcli script.php") + os.Exit(1) + } + + os.Exit(frankenphp.ExecuteScriptCLI(os.Args[1], os.Args)) +} diff --git a/testdata/command.php b/testdata/command.php index 65b3aa64f..155e3cc80 100644 --- a/testdata/command.php +++ b/testdata/command.php @@ -1,3 +1,6 @@ Date: Wed, 4 Oct 2023 14:10:16 +0200 Subject: [PATCH 3/8] debug --- frankenphp_test.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/frankenphp_test.go b/frankenphp_test.go index 05e9b69e5..f18a0ebf4 100644 --- a/frankenphp_test.go +++ b/frankenphp_test.go @@ -13,6 +13,7 @@ import ( "net/url" "os" "os/exec" + "runtime" "strconv" "strings" "sync" @@ -553,6 +554,11 @@ func testFiberNoCgo(t *testing.T, opts *testOptions) { } func TestExecuteScriptCLI(t *testing.T) { + path, err := exec.LookPath("go") + assert.NoError(t, err) + t.Logf("Go path: %s\n", path) + t.Logf("Go arch: %s\n", runtime.GOARCH) + cmd := exec.Command("go", "run", "internal/testcli/main.go", "testdata/command.php", "foo", "bar") stdoutStderr, err := cmd.CombinedOutput() assert.Error(t, err) From a15dca54cfa71d891382f1dd56d717748df03bf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Thu, 5 Oct 2023 16:37:34 +0200 Subject: [PATCH 4/8] fix tests --- .github/workflows/tests.yml | 4 ++++ frankenphp_test.go | 15 ++++++++------- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f002157f4..7b517409f 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -41,6 +41,10 @@ jobs: run: go build env: GOEXPERIMENT: cgocheck2 + - + name: Build testcli binary + working-directory: internal/testcli/ + run: go build - name: Run library tests run: go test -race -v ./... diff --git a/frankenphp_test.go b/frankenphp_test.go index f18a0ebf4..a899b0665 100644 --- a/frankenphp_test.go +++ b/frankenphp_test.go @@ -13,7 +13,6 @@ import ( "net/url" "os" "os/exec" - "runtime" "strconv" "strings" "sync" @@ -554,21 +553,23 @@ func testFiberNoCgo(t *testing.T, opts *testOptions) { } func TestExecuteScriptCLI(t *testing.T) { - path, err := exec.LookPath("go") - assert.NoError(t, err) - t.Logf("Go path: %s\n", path) - t.Logf("Go arch: %s\n", runtime.GOARCH) + if _, err := os.Stat("internal/testcli/testcli"); err != nil { + t.Skip("internal/testcli/testcli has not been compiled, run `cd internal/testcli/ && go build`") + } - cmd := exec.Command("go", "run", "internal/testcli/main.go", "testdata/command.php", "foo", "bar") + cmd := exec.Command("internal/testcli/testcli", "testdata/command.php", "foo", "bar") stdoutStderr, err := cmd.CombinedOutput() assert.Error(t, err) + if exitError, ok := err.(*exec.ExitError); ok { + assert.Equal(t, 3, exitError.ExitCode()) + } + stdoutStderrStr := string(stdoutStderr) assert.Contains(t, stdoutStderrStr, `"foo"`) assert.Contains(t, stdoutStderrStr, `"bar"`) assert.Contains(t, stdoutStderrStr, "From the CLI") - assert.Contains(t, stdoutStderrStr, "exit status 3") } func ExampleServeHTTP() { From 8957b4b9632424863372f1cb5c0eb93e8ee5b5e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Fri, 6 Oct 2023 00:22:30 +0200 Subject: [PATCH 5/8] Caddy php-cli command --- caddy/php-cli.go | 36 +++++++++++++++++++++++++++++ caddy/{command.go => php-server.go} | 2 +- frankenphp.c | 2 ++ 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 caddy/php-cli.go rename caddy/{command.go => php-server.go} (99%) diff --git a/caddy/php-cli.go b/caddy/php-cli.go new file mode 100644 index 000000000..2f0ba6681 --- /dev/null +++ b/caddy/php-cli.go @@ -0,0 +1,36 @@ +package caddy + +import ( + "errors" + "os" + + caddycmd "github.com/caddyserver/caddy/v2/cmd" + "github.com/dunglas/frankenphp" + + "github.com/spf13/cobra" +) + +func init() { + caddycmd.RegisterCommand(caddycmd.Command{ + Name: "php-cli", + Usage: "script.php [args ...]", + Short: "Runs a PHP command", + Long: ` +Executes a PHP script similarly to the CLI SAPI.`, + CobraFunc: func(cmd *cobra.Command) { + cmd.RunE = caddycmd.WrapCommandFuncForCobra(cmdPHPCLI) + }, + }) +} + +func cmdPHPCLI(fs caddycmd.Flags) (int, error) { + args := fs.Args() + if len(args) < 1 { + return 1, errors.New("the path to the PHP script is required") + } + + status := frankenphp.ExecuteScriptCLI(args[0], args) + os.Exit(status) + + return status, nil +} diff --git a/caddy/command.go b/caddy/php-server.go similarity index 99% rename from caddy/command.go rename to caddy/php-server.go index 49e3e6170..a6b3fbbcc 100644 --- a/caddy/command.go +++ b/caddy/php-server.go @@ -23,7 +23,7 @@ import ( func init() { caddycmd.RegisterCommand(caddycmd.Command{ Name: "php-server", - Usage: "[--domain ] [--root ] [--listen ] [--access-log]", + Usage: "[--domain ] [--root ] [--listen ] [--access-log] [--debug] [--no-compress]", Short: "Spins up a production-ready PHP server", Long: ` A simple but production-ready PHP server. Useful for quick deployments, diff --git a/frankenphp.c b/frankenphp.c index 102e3ac64..ac11fb96d 100644 --- a/frankenphp.c +++ b/frankenphp.c @@ -672,6 +672,8 @@ int frankenphp_execute_script_cli(char *script, int argc, char **argv) { int exit_status; + // The SAPI name "cli" is hardcoded into too many programs... let's usurp it. + php_embed_module.name = "cli"; php_embed_module.pretty_name = "PHP CLI embedded in FrankenPHP"; php_embed_init(argc, argv); From 2f97ffc64f59011089b42636b277296edc075c66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Fri, 6 Oct 2023 19:10:08 +0200 Subject: [PATCH 6/8] use thread --- frankenphp.c | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/frankenphp.c b/frankenphp.c index ac11fb96d..9f3c7e23e 100644 --- a/frankenphp.c +++ b/frankenphp.c @@ -665,28 +665,52 @@ int frankenphp_execute_script(const char* file_name) return status; } -int frankenphp_execute_script_cli(char *script, int argc, char **argv) { - if (fork() == 0) { - return SUCCESS; - } +// Use global variables to store CLI arguments to prevent useless allocations +char *cliScript; +int cliArgc; +char **cliArgv; - int exit_status; +static void * execute_script_cli(void *arg) { + void *exit_status; // The SAPI name "cli" is hardcoded into too many programs... let's usurp it. php_embed_module.name = "cli"; php_embed_module.pretty_name = "PHP CLI embedded in FrankenPHP"; - php_embed_init(argc, argv); + php_embed_init(cliArgc, cliArgv); zend_first_try { zend_file_handle file_handle; - zend_stream_init_filename(&file_handle, script); + zend_stream_init_filename(&file_handle, cliScript); php_execute_script(&file_handle); } zend_end_try(); - exit_status = EG(exit_status); + exit_status = (void *) (intptr_t) EG(exit_status); php_embed_shutdown(); return exit_status; } + +int frankenphp_execute_script_cli(char *script, int argc, char **argv) { + pthread_t thread; + int err; + void *exit_status; + + cliScript = script; + cliArgc = argc; + cliArgv = argv; + + // Start the script in a dedicated thread to prevent conflicts between Go and PHP signal handlers + err = pthread_create(&thread, NULL, execute_script_cli, NULL); + if (err != 0) { + return err; + } + + err = pthread_join(thread, &exit_status); + if (err != 0) { + return err; + } + + return (intptr_t) exit_status; +} From bc88ade683dcbf8ce50552c35447bf17b4ba9a87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Sat, 7 Oct 2023 12:03:31 +0200 Subject: [PATCH 7/8] $_SERVER and input streams support --- caddy/php-cli.go | 3 +- frankenphp.c | 96 ++++++++++++++++++++++++++++++++++++++++---- testdata/command.php | 2 +- 3 files changed, 91 insertions(+), 10 deletions(-) diff --git a/caddy/php-cli.go b/caddy/php-cli.go index 2f0ba6681..0d9f38e16 100644 --- a/caddy/php-cli.go +++ b/caddy/php-cli.go @@ -18,13 +18,14 @@ func init() { Long: ` Executes a PHP script similarly to the CLI SAPI.`, CobraFunc: func(cmd *cobra.Command) { + cmd.DisableFlagParsing = true cmd.RunE = caddycmd.WrapCommandFuncForCobra(cmdPHPCLI) }, }) } func cmdPHPCLI(fs caddycmd.Flags) (int, error) { - args := fs.Args() + args := os.Args[2:] if len(args) < 1 { return 1, errors.New("the path to the PHP script is required") } diff --git a/frankenphp.c b/frankenphp.c index 9f3c7e23e..5b5ea59f1 100644 --- a/frankenphp.c +++ b/frankenphp.c @@ -666,9 +666,86 @@ int frankenphp_execute_script(const char* file_name) } // Use global variables to store CLI arguments to prevent useless allocations -char *cliScript; -int cliArgc; -char **cliArgv; +static char *cli_script; +static int cli_argc; +static char **cli_argv; + +// Adapted from https://github.com/php/php-src/sapi/cli/php_cli.c (The PHP Group, The PHP License) +static void cli_register_file_handles(bool no_close) /* {{{ */ +{ + php_stream *s_in, *s_out, *s_err; + php_stream_context *sc_in=NULL, *sc_out=NULL, *sc_err=NULL; + zend_constant ic, oc, ec; + + s_in = php_stream_open_wrapper_ex("php://stdin", "rb", 0, NULL, sc_in); + s_out = php_stream_open_wrapper_ex("php://stdout", "wb", 0, NULL, sc_out); + s_err = php_stream_open_wrapper_ex("php://stderr", "wb", 0, NULL, sc_err); + + if (s_in==NULL || s_out==NULL || s_err==NULL) { + if (s_in) php_stream_close(s_in); + if (s_out) php_stream_close(s_out); + if (s_err) php_stream_close(s_err); + return; + } + + if (no_close) { + s_in->flags |= PHP_STREAM_FLAG_NO_CLOSE; + s_out->flags |= PHP_STREAM_FLAG_NO_CLOSE; + s_err->flags |= PHP_STREAM_FLAG_NO_CLOSE; + } + + //s_in_process = s_in; + + php_stream_to_zval(s_in, &ic.value); + php_stream_to_zval(s_out, &oc.value); + php_stream_to_zval(s_err, &ec.value); + + ZEND_CONSTANT_SET_FLAGS(&ic, CONST_CS, 0); + ic.name = zend_string_init_interned("STDIN", sizeof("STDIN")-1, 0); + zend_register_constant(&ic); + + ZEND_CONSTANT_SET_FLAGS(&oc, CONST_CS, 0); + oc.name = zend_string_init_interned("STDOUT", sizeof("STDOUT")-1, 0); + zend_register_constant(&oc); + + ZEND_CONSTANT_SET_FLAGS(&ec, CONST_CS, 0); + ec.name = zend_string_init_interned("STDERR", sizeof("STDERR")-1, 0); + zend_register_constant(&ec); +} +/* }}} */ + +static void sapi_cli_register_variables(zval *track_vars_array) /* {{{ */ +{ + size_t len; + char *docroot = ""; + + /* In CGI mode, we consider the environment to be a part of the server + * variables + */ + php_import_environment_variables(track_vars_array); + + /* Build the special-case PHP_SELF variable for the CLI version */ + len = strlen(cli_script); + if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF", &cli_script, len, &len)) { + php_register_variable("PHP_SELF", cli_script, track_vars_array); + } + if (sapi_module.input_filter(PARSE_SERVER, "SCRIPT_NAME", &cli_script, len, &len)) { + php_register_variable("SCRIPT_NAME", cli_script, track_vars_array); + } + /* filenames are empty for stdin */ + if (sapi_module.input_filter(PARSE_SERVER, "SCRIPT_FILENAME", &cli_script, len, &len)) { + php_register_variable("SCRIPT_FILENAME", cli_script, track_vars_array); + } + if (sapi_module.input_filter(PARSE_SERVER, "PATH_TRANSLATED", &cli_script, len, &len)) { + php_register_variable("PATH_TRANSLATED", cli_script, track_vars_array); + } + /* just make it available */ + len = 0U; + if (sapi_module.input_filter(PARSE_SERVER, "DOCUMENT_ROOT", &docroot, len, &len)) { + php_register_variable("DOCUMENT_ROOT", docroot, track_vars_array); + } +} +/* }}} */ static void * execute_script_cli(void *arg) { void *exit_status; @@ -676,11 +753,14 @@ static void * execute_script_cli(void *arg) { // The SAPI name "cli" is hardcoded into too many programs... let's usurp it. php_embed_module.name = "cli"; php_embed_module.pretty_name = "PHP CLI embedded in FrankenPHP"; + php_embed_module.register_server_variables = sapi_cli_register_variables; + + php_embed_init(cli_argc, cli_argv); - php_embed_init(cliArgc, cliArgv); + cli_register_file_handles(false); zend_first_try { zend_file_handle file_handle; - zend_stream_init_filename(&file_handle, cliScript); + zend_stream_init_filename(&file_handle, cli_script); php_execute_script(&file_handle); } zend_end_try(); @@ -697,9 +777,9 @@ int frankenphp_execute_script_cli(char *script, int argc, char **argv) { int err; void *exit_status; - cliScript = script; - cliArgc = argc; - cliArgv = argv; + cli_script = script; + cli_argc = argc; + cli_argv = argv; // Start the script in a dedicated thread to prevent conflicts between Go and PHP signal handlers err = pthread_create(&thread, NULL, execute_script_cli, NULL); diff --git a/testdata/command.php b/testdata/command.php index 155e3cc80..75fcf136b 100644 --- a/testdata/command.php +++ b/testdata/command.php @@ -1,6 +1,6 @@ Date: Mon, 9 Oct 2023 12:04:31 +0200 Subject: [PATCH 8/8] Update frankenphp.c Co-authored-by: Francis Lavoie --- frankenphp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frankenphp.c b/frankenphp.c index 5b5ea59f1..316ab3e49 100644 --- a/frankenphp.c +++ b/frankenphp.c @@ -755,10 +755,10 @@ static void * execute_script_cli(void *arg) { php_embed_module.pretty_name = "PHP CLI embedded in FrankenPHP"; php_embed_module.register_server_variables = sapi_cli_register_variables; - php_embed_init(cli_argc, cli_argv); + php_embed_init(cli_argc, cli_argv); cli_register_file_handles(false); - zend_first_try { + zend_first_try { zend_file_handle file_handle; zend_stream_init_filename(&file_handle, cli_script);