diff options
Diffstat (limited to 'crates/shirabe-php-shim/src')
| -rw-r--r-- | crates/shirabe-php-shim/src/env.rs | 144 |
1 files changed, 67 insertions, 77 deletions
diff --git a/crates/shirabe-php-shim/src/env.rs b/crates/shirabe-php-shim/src/env.rs index 62dc666..cf0c659 100644 --- a/crates/shirabe-php-shim/src/env.rs +++ b/crates/shirabe-php-shim/src/env.rs @@ -1,100 +1,90 @@ -use crate::PhpMixed; -use indexmap::IndexMap; +//! Porting rules for PHP environment variables: see `docs/dev/env-vars-porting.md`. -pub fn getenv(_name: &str) -> Option<String> { - std::env::var(_name).ok() +pub fn getenv_all() -> std::env::VarsOs { + std::env::vars_os() } -// TODO(phase-c): only the simple `^(\w+)(=(.+))?$` form is supported. -pub fn putenv(setting: &str) -> bool { - let is_word = - |s: &str| !s.is_empty() && s.bytes().all(|b| b.is_ascii_alphanumeric() || b == b'_'); - // A setting without `=` deletes the variable, mirroring PHP's putenv('NAME'). - match setting.split_once('=') { - Some((name, value)) => { - if !is_word(name) { - panic!("putenv: unsupported setting format: {setting:?}"); - } - unsafe { - std::env::set_var(name, value); - } - } - None => { - if !is_word(setting) { - panic!("putenv: unsupported setting format: {setting:?}"); - } - unsafe { - std::env::remove_var(setting); - } - } - } - true +pub fn getenv<K: AsRef<std::ffi::OsStr>>(key: K) -> Option<std::ffi::OsString> { + std::env::var_os(key) } -/// PHP superglobal $_SERVER access. In the CLI SAPI $_SERVER is populated from -/// the environment, which is the only source modeled here. -pub fn server_get(name: &str) -> Option<String> { - // TODO: is var_os() better? - std::env::var(name).ok() +pub unsafe fn putenv<K: AsRef<std::ffi::OsStr>, V: AsRef<std::ffi::OsStr>>(key: K, value: V) { + // TODO: validate key and value format to avoid panic? + unsafe { std::env::set_var(key, value) } } -// TODO(php-runtime): modify the real PHP's $_SERVER. -pub fn server_set(_name: &str, _value: String) {} - -// TODO(php-runtime): modify the real PHP's $_SERVER. -pub fn server_unset(_name: &str) {} - -pub fn server_contains_key(name: &str) -> bool { - std::env::var_os(name).is_some() +pub unsafe fn putenv_clear<K: AsRef<std::ffi::OsStr>>(key: K) { + // TODO: validate key and value format to avoid panic? + unsafe { std::env::remove_var(key) } } -/// PHP superglobal $_ENV access. -pub fn env_get(name: &str) -> Option<String> { - // TODO: is var_os() better? - std::env::var(name).ok() +pub struct Superglobal { + vars: indexmap::IndexMap<std::ffi::OsString, std::ffi::OsString>, } -// TODO(php-runtime): modify the real PHP's $_ENV. -pub fn env_set(_name: &str, _value: String) {} +pub struct SuperglobalServer(Superglobal); -// TODO(php-runtime): modify the real PHP's $_ENV. -pub fn env_unset(_name: &str) {} +impl Superglobal { + fn from_env_vars() -> Self { + let vars = std::env::vars_os().collect(); + Self { vars } + } -pub fn env_contains_key(name: &str) -> bool { - std::env::var_os(name).is_some() -} + pub fn get_all(&self) -> impl Iterator<Item = (std::ffi::OsString, std::ffi::OsString)> + '_ { + self.vars.iter().map(|(k, v)| (k.clone(), v.clone())) + } -/// PHP `getenv()` with no argument: all environment variables. -pub fn getenv_all() -> IndexMap<String, String> { - todo!() -} + pub fn get<K: AsRef<std::ffi::OsStr>>(&self, key: K) -> Option<std::ffi::OsString> { + self.vars.get(key.as_ref()).cloned() + } -/// PHP superglobal `$_ENV`. -pub fn php_env() -> IndexMap<String, PhpMixed> { - todo!() -} + pub fn put(&mut self, key: std::ffi::OsString, value: std::ffi::OsString) { + self.vars.insert(key, value); + } -/// PHP superglobal `$_SERVER`. -pub fn php_server() -> IndexMap<String, PhpMixed> { - todo!() + pub fn clear<K: AsRef<std::ffi::OsStr>>(&mut self, key: K) { + self.vars.shift_remove(key.as_ref()); + } } -pub fn server(key: &str) -> String { - if key == "PHP_SELF" { - return server_php_self(); +impl SuperglobalServer { + fn from_env_vars() -> Self { + Self(Superglobal::from_env_vars()) } - server_get(key).unwrap_or_default() -} -pub fn server_argv() -> Vec<String> { - std::env::args().collect() -} + pub fn get_all(&self) -> impl Iterator<Item = (std::ffi::OsString, std::ffi::OsString)> + '_ { + self.0.get_all() + } -pub fn server_php_self() -> String { - // CLI SAPI: $_SERVER['PHP_SELF'] is the path of the executed script, i.e. argv[0]. - std::env::args().next().unwrap_or_default() -} + pub fn get<K: AsRef<std::ffi::OsStr>>(&self, key: K) -> Option<std::ffi::OsString> { + self.0.get(key) + } + + pub fn put(&mut self, key: std::ffi::OsString, value: std::ffi::OsString) { + self.0.put(key, value) + } + + pub fn clear<K: AsRef<std::ffi::OsStr>>(&mut self, key: K) { + self.0.clear(key) + } + + pub fn argv(&self) -> std::env::ArgsOs { + std::env::args_os() + } -pub fn server_shell() -> Option<String> { - todo!() + pub fn php_self(&self) -> Option<std::ffi::OsString> { + self.argv().next() + } } + +/// PHP superglobal $_SERVER. $_SERVER is a snapshot at startup. Modifying it does not affect the +/// real environment variables, while putenv() does. +/// TODO(php-runtime): modify the real PHP's $_SERVER. +pub static PHP_SERVER: std::sync::LazyLock<std::sync::Mutex<SuperglobalServer>> = + std::sync::LazyLock::new(|| std::sync::Mutex::new(SuperglobalServer::from_env_vars())); + +/// PHP superglobal $_ENV. $_ENV is a snapshot at startup. Modifying it does not affect the real +/// environment variables, while putenv() does. +/// TODO(php-runtime): modify the real PHP's $_ENV. +pub static PHP_ENV: std::sync::LazyLock<std::sync::Mutex<Superglobal>> = + std::sync::LazyLock::new(|| std::sync::Mutex::new(Superglobal::from_env_vars())); |
