@@ -92,6 +92,10 @@ HashTable *main_thread_env = NULL;
9292__thread uintptr_t thread_index ;
9393__thread bool is_worker_thread = false;
9494__thread HashTable * sandboxed_env = NULL ;
95+ /* prepared_env holds entries from php(_server)'s `env KEY VAL`,
96+ * so they can be merged into $_ENV when 'E' is in
97+ * variables_order. Separate from putenv() so we don't leak into $_ENV */
98+ __thread HashTable * prepared_env = NULL ;
9599
96100/* Published via SG(server_context) so ext-parallel children, which inherit
97101 * the parent's SG(server_context), can route SAPI callbacks back to the
@@ -429,9 +433,16 @@ bool frankenphp_shutdown_dummy_request(void) {
429433}
430434
431435void get_full_env (zval * track_vars_array ) {
432- zend_hash_extend (Z_ARR_P (track_vars_array ),
433- zend_hash_num_elements (main_thread_env ), 0 );
436+ size_t total = zend_hash_num_elements (main_thread_env );
437+ if (prepared_env != NULL ) {
438+ // perf: doesn't matter if we get the exact count, just >= needed
439+ total += zend_hash_num_elements (prepared_env );
440+ }
441+ zend_hash_extend (Z_ARR_P (track_vars_array ), total , 0 );
434442 zend_hash_copy (Z_ARR_P (track_vars_array ), main_thread_env , NULL );
443+ if (prepared_env != NULL ) {
444+ zend_hash_copy (Z_ARR_P (track_vars_array ), prepared_env , NULL );
445+ }
435446}
436447
437448/* Adapted from php_request_startup() */
@@ -1239,6 +1250,31 @@ static inline void reset_sandboxed_environment() {
12391250 zend_hash_release (sandboxed_env );
12401251 sandboxed_env = NULL ;
12411252 }
1253+ if (prepared_env != NULL ) {
1254+ zend_hash_release (prepared_env );
1255+ prepared_env = NULL ;
1256+ }
1257+ }
1258+
1259+ /* Adds a key/value pair to the per-thread sandboxed environment so it becomes
1260+ * visible to getenv()/$_ENV. Used to expose env vars declared in the php(_server)
1261+ * directive, which would otherwise only appear in $_SERVER. */
1262+ void frankenphp_add_to_sandboxed_env (char * name , size_t name_len , char * val ,
1263+ size_t val_len ) {
1264+ if (sandboxed_env == NULL ) {
1265+ sandboxed_env = zend_array_dup (main_thread_env );
1266+ }
1267+ zval zv = {0 };
1268+ ZVAL_STRINGL (& zv , val , val_len );
1269+ zend_hash_str_update (sandboxed_env , name , name_len , & zv );
1270+
1271+ if (prepared_env == NULL ) {
1272+ ALLOC_HASHTABLE (prepared_env );
1273+ zend_hash_init (prepared_env , 8 , NULL , ZVAL_PTR_DTOR , 0 );
1274+ }
1275+ zval zv2 = {0 };
1276+ ZVAL_STRINGL (& zv2 , val , val_len );
1277+ zend_hash_str_update (prepared_env , name , name_len , & zv2 );
12421278}
12431279
12441280static void * php_thread (void * arg ) {
0 commit comments