Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion frankenphp.c
Original file line number Diff line number Diff line change
Expand Up @@ -968,7 +968,8 @@ static void *php_main(void *arg) {
#endif

sapi_startup(&frankenphp_sapi_module);

frankenphp_sapi_module.php_ini_ignore = go_get_php_ini_ignore();
frankenphp_sapi_module.php_ini_ignore_cwd = go_get_php_ini_ignore_cwd();
#ifndef ZEND_MAX_EXECUTION_TIMERS
#if (PHP_VERSION_ID >= 80300)
frankenphp_sapi_module.ini_entries = HARDCODED_INI;
Expand Down
2 changes: 1 addition & 1 deletion frankenphp.go
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ func Init(options ...Option) error {
}

requestChan = make(chan *http.Request, opt.numThreads)
if err := initPHPThreads(totalThreadCount); err != nil {
if err := initPHPThreads(totalThreadCount, opt.phpIniIgnore, opt.phpIniIgnoreCwd); err != nil {
return err
}

Expand Down
49 changes: 49 additions & 0 deletions frankenphp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ type testOptions struct {
realServer bool
logger *zap.Logger
initOpts []frankenphp.Option
chdirToTest bool
}

func runTest(t *testing.T, test func(func(http.ResponseWriter, *http.Request), *httptest.Server, int), opts *testOptions) {
Expand All @@ -58,6 +59,14 @@ func runTest(t *testing.T, test func(func(http.ResponseWriter, *http.Request), *
cwd, _ := os.Getwd()
testDataDir := cwd + "/testdata/"

if opts.chdirToTest {
errChdir := os.Chdir(testDataDir)
require.Nil(t, errChdir)
defer func() {
require.Nil(t, os.Chdir(cwd))
}()
}

if opts.logger == nil {
opts.logger = zaptest.NewLogger(t)
}
Expand Down Expand Up @@ -978,6 +987,46 @@ func TestFileStreamInWorkerMode(t *testing.T) {
}, &testOptions{workerScript: "file-stream.php", nbParallelRequests: 1, nbWorkers: 1})
}

func TestSearchIniDefault(t *testing.T) {
runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) {
req := httptest.NewRequest("GET", "http://example.com/php_ini_loaded_file.php", nil)
w := httptest.NewRecorder()
handler(w, req)

resp := w.Result()
body, _ := io.ReadAll(resp.Body)

assert.Equal(t, "cwd", string(body))
}, &testOptions{chdirToTest: true})
}

func TestSearchIniIPHPIniIgnoreCwd(t *testing.T) {
runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) {
req := httptest.NewRequest("GET", "http://example.com/php_ini_loaded_file.php", nil)
w := httptest.NewRecorder()
handler(w, req)

resp := w.Result()
body, _ := io.ReadAll(resp.Body)
bodyString := string(body)
// none - if not set global php.ini
assert.True(t, bodyString == "none" || bodyString == "global")
}, &testOptions{chdirToTest: true, initOpts: []frankenphp.Option{frankenphp.WithPHPIniIgnoreCwd(true)}})
}

func TestSearchIniPHPIniIgnore(t *testing.T) {
runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) {
req := httptest.NewRequest("GET", "http://example.com/php_ini_loaded_file.php", nil)
w := httptest.NewRecorder()
handler(w, req)

resp := w.Result()
body, _ := io.ReadAll(resp.Body)

assert.Equal(t, "none", string(body))
}, &testOptions{chdirToTest: true, initOpts: []frankenphp.Option{frankenphp.WithPHPIniIgnore(true)}})
}

// To run this fuzzing test use: go test -fuzz FuzzRequest
// TODO: Cover more potential cases
func FuzzRequest(f *testing.F) {
Expand Down
21 changes: 21 additions & 0 deletions options.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ type opt struct {
workers []workerOpt
logger *zap.Logger
metrics Metrics
// sapi options
phpIniIgnore bool
phpIniIgnoreCwd bool
}

type workerOpt struct {
Expand Down Expand Up @@ -58,3 +61,21 @@ func WithLogger(l *zap.Logger) Option {
return nil
}
}

// WithPHPIniIgnore don't look for php.ini
func WithPHPIniIgnore(ignore bool) Option {
return func(o *opt) error {
o.phpIniIgnore = ignore

return nil
}
}

// WithPHPIniIgnoreCwd don't look for php.ini in the current directory
func WithPHPIniIgnoreCwd(ignoreCwd bool) Option {
return func(o *opt) error {
o.phpIniIgnoreCwd = ignoreCwd

return nil
}
}
30 changes: 26 additions & 4 deletions phpmainthread.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ type phpMainThread struct {
state *threadState
done chan struct{}
numThreads int
phpIniIgnore bool
phpIniIgnoreCwd bool
commonHeaders map[string]*C.zend_string
knownServerKeys map[string]*C.zend_string
}
Expand All @@ -25,11 +27,13 @@ var (
)

// reserve a fixed number of PHP threads on the Go side
func initPHPThreads(numThreads int) error {
func initPHPThreads(numThreads int, phpIniIgnore bool, phpIniIgnoreCwd bool) error {
mainThread = &phpMainThread{
state: newThreadState(),
done: make(chan struct{}),
numThreads: numThreads,
state: newThreadState(),
done: make(chan struct{}),
numThreads: numThreads,
phpIniIgnore: phpIniIgnore,
phpIniIgnoreCwd: phpIniIgnoreCwd,
}
phpThreads = make([]*phpThread, numThreads)

Expand Down Expand Up @@ -124,3 +128,21 @@ func go_frankenphp_main_thread_is_ready() {
func go_frankenphp_shutdown_main_thread() {
mainThread.state.set(stateDone)
}

//export go_get_php_ini_ignore
func go_get_php_ini_ignore() C.int {
if mainThread.phpIniIgnore {
return C.int(1)
} else {
return C.int(0)
}
}

//export go_get_php_ini_ignore_cwd
func go_get_php_ini_ignore_cwd() C.int {
if mainThread.phpIniIgnoreCwd {
return C.int(1)
} else {
return C.int(0)
}
}
8 changes: 4 additions & 4 deletions phpmainthread_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ import (
var testDataPath, _ = filepath.Abs("./testdata")

func TestStartAndStopTheMainThreadWithOneInactiveThread(t *testing.T) {
logger = zap.NewNop() // the logger needs to not be nil
assert.NoError(t, initPHPThreads(1)) // reserve 1 thread
logger = zap.NewNop() // the logger needs to not be nil
assert.NoError(t, initPHPThreads(1, false, false)) // reserve 1 thread

assert.Len(t, phpThreads, 1)
assert.Equal(t, 0, phpThreads[0].threadIndex)
Expand All @@ -31,7 +31,7 @@ func TestStartAndStopTheMainThreadWithOneInactiveThread(t *testing.T) {

func TestTransitionRegularThreadToWorkerThread(t *testing.T) {
logger = zap.NewNop()
assert.NoError(t, initPHPThreads(1))
assert.NoError(t, initPHPThreads(1, false, false))

// transition to regular thread
convertToRegularThread(phpThreads[0])
Expand All @@ -54,7 +54,7 @@ func TestTransitionRegularThreadToWorkerThread(t *testing.T) {

func TestTransitionAThreadBetween2DifferentWorkers(t *testing.T) {
logger = zap.NewNop()
assert.NoError(t, initPHPThreads(1))
assert.NoError(t, initPHPThreads(1, false, false))
firstWorker := getDummyWorker("transition-worker-1.php")
secondWorker := getDummyWorker("transition-worker-2.php")

Expand Down
Empty file added testdata/php.ini
Empty file.
14 changes: 14 additions & 0 deletions testdata/php_ini_loaded_file.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

require_once __DIR__ . '/_executor.php';

return function () {
$ini = php_ini_loaded_file();
if ($ini === false) {
echo 'none';
} elseif (str_contains($ini, "testdata/php.ini")) {
echo 'cwd';
} else {
echo 'global';
}
};