env.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. package frankenphp
  2. // #cgo nocallback frankenphp_init_persistent_string
  3. // #cgo nocallback frankenphp_add_assoc_str_ex
  4. // #cgo noescape frankenphp_init_persistent_string
  5. // #cgo noescape frankenphp_add_assoc_str_ex
  6. // #include "frankenphp.h"
  7. import "C"
  8. import (
  9. "os"
  10. "strings"
  11. "unsafe"
  12. )
  13. func initializeEnv() map[string]*C.zend_string {
  14. env := os.Environ()
  15. envMap := make(map[string]*C.zend_string, len(env))
  16. for _, envVar := range env {
  17. key, val, _ := strings.Cut(envVar, "=")
  18. envMap[key] = C.frankenphp_init_persistent_string(toUnsafeChar(val), C.size_t(len(val)))
  19. }
  20. return envMap
  21. }
  22. // get the main thread env or the thread specific env
  23. func getSandboxedEnv(thread *phpThread) map[string]*C.zend_string {
  24. if thread.sandboxedEnv != nil {
  25. return thread.sandboxedEnv
  26. }
  27. return mainThread.sandboxedEnv
  28. }
  29. func clearSandboxedEnv(thread *phpThread) {
  30. if thread.sandboxedEnv == nil {
  31. return
  32. }
  33. for key, val := range thread.sandboxedEnv {
  34. valInMainThread, ok := mainThread.sandboxedEnv[key]
  35. if !ok || val != valInMainThread {
  36. C.free(unsafe.Pointer(val))
  37. }
  38. }
  39. thread.sandboxedEnv = nil
  40. }
  41. // if an env var already exists, it needs to be freed
  42. func removeEnvFromThread(thread *phpThread, key string) {
  43. valueInThread, existsInThread := thread.sandboxedEnv[key]
  44. if !existsInThread {
  45. return
  46. }
  47. valueInMainThread, ok := mainThread.sandboxedEnv[key]
  48. if !ok || valueInThread != valueInMainThread {
  49. C.free(unsafe.Pointer(valueInThread))
  50. }
  51. delete(thread.sandboxedEnv, key)
  52. }
  53. // copy the main thread env to the thread specific env
  54. func cloneSandboxedEnv(thread *phpThread) {
  55. if thread.sandboxedEnv != nil {
  56. return
  57. }
  58. thread.sandboxedEnv = make(map[string]*C.zend_string, len(mainThread.sandboxedEnv))
  59. for key, value := range mainThread.sandboxedEnv {
  60. thread.sandboxedEnv[key] = value
  61. }
  62. }
  63. //export go_putenv
  64. func go_putenv(threadIndex C.uintptr_t, str *C.char, length C.int) C.bool {
  65. thread := phpThreads[threadIndex]
  66. envString := C.GoStringN(str, length)
  67. cloneSandboxedEnv(thread)
  68. // Check if '=' is present in the string
  69. if key, val, found := strings.Cut(envString, "="); found {
  70. removeEnvFromThread(thread, key)
  71. thread.sandboxedEnv[key] = C.frankenphp_init_persistent_string(toUnsafeChar(val), C.size_t(len(val)))
  72. return os.Setenv(key, val) == nil
  73. }
  74. // No '=', unset the environment variable
  75. removeEnvFromThread(thread, envString)
  76. return os.Unsetenv(envString) == nil
  77. }
  78. //export go_getfullenv
  79. func go_getfullenv(threadIndex C.uintptr_t, trackVarsArray *C.zval) {
  80. thread := phpThreads[threadIndex]
  81. env := getSandboxedEnv(thread)
  82. for key, val := range env {
  83. C.frankenphp_add_assoc_str_ex(trackVarsArray, toUnsafeChar(key), C.size_t(len(key)), val)
  84. }
  85. }
  86. //export go_getenv
  87. func go_getenv(threadIndex C.uintptr_t, name *C.char) (C.bool, *C.zend_string) {
  88. thread := phpThreads[threadIndex]
  89. // Get the environment variable value
  90. envValue, exists := getSandboxedEnv(thread)[C.GoString(name)]
  91. if !exists {
  92. // Environment variable does not exist
  93. return false, nil // Return 0 to indicate failure
  94. }
  95. return true, envValue // Return 1 to indicate success
  96. }