|
@@ -1,5 +1,9 @@
|
|
|
package frankenphp
|
|
|
|
|
|
+// #cgo nocallback frankenphp_init_persistent_string
|
|
|
+// #cgo nocallback frankenphp_add_assoc_str_ex
|
|
|
+// #cgo noescape frankenphp_init_persistent_string
|
|
|
+// #cgo noescape frankenphp_add_assoc_str_ex
|
|
|
// #include "frankenphp.h"
|
|
|
import "C"
|
|
|
import (
|
|
@@ -8,67 +12,106 @@ import (
|
|
|
"unsafe"
|
|
|
)
|
|
|
|
|
|
+func initializeEnv() map[string]*C.zend_string {
|
|
|
+ env := os.Environ()
|
|
|
+ envMap := make(map[string]*C.zend_string, len(env))
|
|
|
+
|
|
|
+ for _, envVar := range env {
|
|
|
+ key, val, _ := strings.Cut(envVar, "=")
|
|
|
+ envMap[key] = C.frankenphp_init_persistent_string(toUnsafeChar(val), C.size_t(len(val)))
|
|
|
+ }
|
|
|
+
|
|
|
+ return envMap
|
|
|
+}
|
|
|
+
|
|
|
+// get the main thread env or the thread specific env
|
|
|
+func getSandboxedEnv(thread *phpThread) map[string]*C.zend_string {
|
|
|
+ if thread.sandboxedEnv != nil {
|
|
|
+ return thread.sandboxedEnv
|
|
|
+ }
|
|
|
+
|
|
|
+ return mainThread.sandboxedEnv
|
|
|
+}
|
|
|
+
|
|
|
+func clearSandboxedEnv(thread *phpThread) {
|
|
|
+ if thread.sandboxedEnv == nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ for key, val := range thread.sandboxedEnv {
|
|
|
+ valInMainThread, ok := mainThread.sandboxedEnv[key]
|
|
|
+ if !ok || val != valInMainThread {
|
|
|
+ C.free(unsafe.Pointer(val))
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ thread.sandboxedEnv = nil
|
|
|
+}
|
|
|
+
|
|
|
+// if an env var already exists, it needs to be freed
|
|
|
+func removeEnvFromThread(thread *phpThread, key string) {
|
|
|
+ valueInThread, existsInThread := thread.sandboxedEnv[key]
|
|
|
+ if !existsInThread {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ valueInMainThread, ok := mainThread.sandboxedEnv[key]
|
|
|
+ if !ok || valueInThread != valueInMainThread {
|
|
|
+ C.free(unsafe.Pointer(valueInThread))
|
|
|
+ }
|
|
|
+
|
|
|
+ delete(thread.sandboxedEnv, key)
|
|
|
+}
|
|
|
+
|
|
|
+// copy the main thread env to the thread specific env
|
|
|
+func cloneSandboxedEnv(thread *phpThread) {
|
|
|
+ if thread.sandboxedEnv != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ thread.sandboxedEnv = make(map[string]*C.zend_string, len(mainThread.sandboxedEnv))
|
|
|
+ for key, value := range mainThread.sandboxedEnv {
|
|
|
+ thread.sandboxedEnv[key] = value
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
//export go_putenv
|
|
|
-func go_putenv(str *C.char, length C.int) C.bool {
|
|
|
+func go_putenv(threadIndex C.uintptr_t, str *C.char, length C.int) C.bool {
|
|
|
+ thread := phpThreads[threadIndex]
|
|
|
envString := C.GoStringN(str, length)
|
|
|
+ cloneSandboxedEnv(thread)
|
|
|
|
|
|
// Check if '=' is present in the string
|
|
|
if key, val, found := strings.Cut(envString, "="); found {
|
|
|
+ removeEnvFromThread(thread, key)
|
|
|
+ thread.sandboxedEnv[key] = C.frankenphp_init_persistent_string(toUnsafeChar(val), C.size_t(len(val)))
|
|
|
return os.Setenv(key, val) == nil
|
|
|
}
|
|
|
|
|
|
// No '=', unset the environment variable
|
|
|
+ removeEnvFromThread(thread, envString)
|
|
|
return os.Unsetenv(envString) == nil
|
|
|
}
|
|
|
|
|
|
//export go_getfullenv
|
|
|
-func go_getfullenv(threadIndex C.uintptr_t) (*C.go_string, C.size_t) {
|
|
|
+func go_getfullenv(threadIndex C.uintptr_t, trackVarsArray *C.zval) {
|
|
|
thread := phpThreads[threadIndex]
|
|
|
+ env := getSandboxedEnv(thread)
|
|
|
|
|
|
- env := os.Environ()
|
|
|
- goStrings := make([]C.go_string, len(env)*2)
|
|
|
-
|
|
|
- for i, envVar := range env {
|
|
|
- key, val, _ := strings.Cut(envVar, "=")
|
|
|
- goStrings[i*2] = C.go_string{C.size_t(len(key)), thread.pinString(key)}
|
|
|
- goStrings[i*2+1] = C.go_string{C.size_t(len(val)), thread.pinString(val)}
|
|
|
+ for key, val := range env {
|
|
|
+ C.frankenphp_add_assoc_str_ex(trackVarsArray, toUnsafeChar(key), C.size_t(len(key)), val)
|
|
|
}
|
|
|
-
|
|
|
- value := unsafe.SliceData(goStrings)
|
|
|
- thread.Pin(value)
|
|
|
-
|
|
|
- return value, C.size_t(len(env))
|
|
|
}
|
|
|
|
|
|
//export go_getenv
|
|
|
-func go_getenv(threadIndex C.uintptr_t, name *C.go_string) (C.bool, *C.go_string) {
|
|
|
+func go_getenv(threadIndex C.uintptr_t, name *C.char) (C.bool, *C.zend_string) {
|
|
|
thread := phpThreads[threadIndex]
|
|
|
|
|
|
- // Create a byte slice from C string with a specified length
|
|
|
- envName := C.GoStringN(name.data, C.int(name.len))
|
|
|
-
|
|
|
// Get the environment variable value
|
|
|
- envValue, exists := os.LookupEnv(envName)
|
|
|
+ envValue, exists := getSandboxedEnv(thread)[C.GoString(name)]
|
|
|
if !exists {
|
|
|
// Environment variable does not exist
|
|
|
return false, nil // Return 0 to indicate failure
|
|
|
}
|
|
|
|
|
|
- // Convert Go string to C string
|
|
|
- value := &C.go_string{C.size_t(len(envValue)), thread.pinString(envValue)}
|
|
|
- thread.Pin(value)
|
|
|
-
|
|
|
- return true, value // Return 1 to indicate success
|
|
|
-}
|
|
|
-
|
|
|
-//export go_sapi_getenv
|
|
|
-func go_sapi_getenv(threadIndex C.uintptr_t, name *C.go_string) *C.char {
|
|
|
- envName := C.GoStringN(name.data, C.int(name.len))
|
|
|
-
|
|
|
- envValue, exists := os.LookupEnv(envName)
|
|
|
- if !exists {
|
|
|
- return nil
|
|
|
- }
|
|
|
-
|
|
|
- return phpThreads[threadIndex].pinCString(envValue)
|
|
|
+ return true, envValue // Return 1 to indicate success
|
|
|
}
|