use std::ffi::c_char;
use ext_php_rs::args::Arg;
use ext_php_rs::flags::DataType;
use ext_php_rs::types::Zval;
use ext_php_rs::zend::{ExecuteData, SapiGlobals};
use tracing::warn;
use crate::engine::ClavironContext;
use crate::sapi::ServerContext;
pub(crate) extern "C" fn claviron_putenv_handler(
ex: &mut ExecuteData,
retval: &mut Zval,
) {
let mut setting = Arg::new("setting", DataType::String);
if ex.parser().arg(&mut setting).parse().is_err() {
retval.set_bool(false);
return;
}
let Some(setting_str) = setting.val::<String>() else {
retval.set_bool(false);
return;
};
let sapi_globals = SapiGlobals::get();
if sapi_globals.server_context.is_null() {
retval.set_bool(false);
return;
}
let context =
ClavironContext::from_server_context(sapi_globals.server_context);
let Ok(mut overlay) = context.env_overlay.lock() else {
retval.set_bool(false);
return;
};
match setting_str.split_once('=') {
Some((key, value)) => {
overlay.insert(key.to_string(), value.to_string());
}
None => {
overlay.remove(setting_str.as_str());
}
}
retval.set_bool(true);
}
pub(crate) fn override_putenv_handler() {
use ext_php_rs::ffi::{_zend_function, zend_hash_str_find_ptr_lc};
type FunctionPointerHandler =
extern "C" fn(execute_data: *mut ExecuteData, retval: *mut Zval);
type RawFunctionPointerHandler = unsafe extern "C" fn(
execute_data: *mut ext_php_rs::ffi::_zend_execute_data,
retval: *mut ext_php_rs::ffi::_zval_struct,
);
unsafe {
let cg = ext_php_rs::ffi::ext_php_rs_compiler_globals();
if cg.is_null() {
warn!("override_putenv_handler: compiler globals null");
return;
}
let function_table_ptr = (*cg).function_table;
if function_table_ptr.is_null() {
warn!("override_putenv_handler: CG(function_table) is null");
return;
}
let key: &[u8] = b"putenv";
let func_ptr = zend_hash_str_find_ptr_lc(
function_table_ptr,
key.as_ptr() as *const c_char,
key.len(),
) as *mut _zend_function;
if func_ptr.is_null() {
warn!(
"override_putenv_handler: 'putenv' not in CG(function_table); skipping override"
);
return;
}
let new_handler: FunctionPointerHandler =
std::mem::transmute(claviron_putenv_handler as extern "C" fn(_, _));
(*func_ptr).internal_function.handler = Some(std::mem::transmute::<
FunctionPointerHandler,
RawFunctionPointerHandler,
>(new_handler));
#[cfg(debug_assertions)]
tracing::trace!(
"override_putenv_handler: putenv handler swapped to claviron overlay"
);
}
}