diff --git a/allowed_bindings.rs b/allowed_bindings.rs index 7943f33..3e1e7e7 100644 --- a/allowed_bindings.rs +++ b/allowed_bindings.rs @@ -224,8 +224,16 @@ bind! { gc_possible_root, ZEND_ACC_NOT_SERIALIZABLE, executor_globals, + php_core_globals, + core_globals, php_printf, __zend_malloc, tsrm_get_ls_cache, - executor_globals_offset + TRACK_VARS_POST, + TRACK_VARS_GET, + TRACK_VARS_COOKIE, + TRACK_VARS_SERVER, + TRACK_VARS_ENV, + TRACK_VARS_FILES, + TRACK_VARS_REQUEST } diff --git a/src/zend/globals.rs b/src/zend/globals.rs index 7ba76c4..b241cee 100644 --- a/src/zend/globals.rs +++ b/src/zend/globals.rs @@ -5,7 +5,11 @@ use std::ops::{Deref, DerefMut}; use parking_lot::{const_rwlock, RwLock, RwLockReadGuard, RwLockWriteGuard}; use crate::boxed::ZBox; -use crate::ffi::{_zend_executor_globals, ext_php_rs_executor_globals}; +use crate::ffi::{ + _zend_executor_globals, core_globals, ext_php_rs_executor_globals, php_core_globals, + TRACK_VARS_COOKIE, TRACK_VARS_ENV, TRACK_VARS_FILES, TRACK_VARS_GET, TRACK_VARS_POST, + TRACK_VARS_REQUEST, TRACK_VARS_SERVER, +}; use crate::types::{ZendHashTable, ZendObject}; @@ -67,11 +71,98 @@ impl ExecutorGlobals { } } +/// Stores global variables used in the PHP executor. +pub type ProcessGlobals = php_core_globals; + +impl ProcessGlobals { + /// Returns a reference to the PHP process globals. + /// + /// The process globals are guarded by a RwLock. There can be multiple + /// immutable references at one time but only ever one mutable reference. + /// Attempting to retrieve the globals while already holding the global + /// guard will lead to a deadlock. Dropping the globals guard will release + /// the lock. + pub fn get() -> GlobalReadGuard { + // SAFETY: PHP executor globals are statically declared therefore should never + // return an invalid pointer. + let globals = unsafe { &core_globals }; + let guard = PROCESS_GLOBALS_LOCK.read(); + GlobalReadGuard { globals, guard } + } + + /// Returns a mutable reference to the PHP executor globals. + /// + /// The executor globals are guarded by a RwLock. There can be multiple + /// immutable references at one time but only ever one mutable reference. + /// Attempting to retrieve the globals while already holding the global + /// guard will lead to a deadlock. Dropping the globals guard will release + /// the lock. + pub fn get_mut() -> GlobalWriteGuard { + // SAFETY: PHP executor globals are statically declared therefore should never + // return an invalid pointer. + let globals = unsafe { &mut core_globals }; + let guard = PROCESS_GLOBALS_LOCK.write(); + GlobalWriteGuard { globals, guard } + } + + /// Get the HTTP Server variables. Equivalent of $_SERVER. + pub fn http_server_vars(&self) -> Option<&ZendHashTable> { + if self.http_globals[TRACK_VARS_SERVER as usize].is_array() { + self.http_globals[TRACK_VARS_SERVER as usize].array() + } else { + None + } + } + + /// Get the HTTP POST variables. Equivalent of $_POST. + pub fn http_post_vars(&self) -> &ZendHashTable { + self.http_globals[TRACK_VARS_POST as usize] + .array() + .expect("Type is not a ZendArray") + } + + /// Get the HTTP GET variables. Equivalent of $_GET. + pub fn http_get_vars(&self) -> &ZendHashTable { + self.http_globals[TRACK_VARS_GET as usize] + .array() + .expect("Type is not a ZendArray") + } + + /// Get the HTTP Cookie variables. Equivalent of $_COOKIE. + pub fn http_cookie_vars(&self) -> &ZendHashTable { + self.http_globals[TRACK_VARS_COOKIE as usize] + .array() + .expect("Type is not a ZendArray") + } + + /// Get the HTTP Request variables. Equivalent of $_REQUEST. + pub fn http_request_vars(&self) -> &ZendHashTable { + self.http_globals[TRACK_VARS_REQUEST as usize] + .array() + .expect("Type is not a ZendArray") + } + + /// Get the HTTP Environment variables. Equivalent of $_ENV. + pub fn http_env_vars(&self) -> &ZendHashTable { + self.http_globals[TRACK_VARS_ENV as usize] + .array() + .expect("Type is not a ZendArray") + } + + /// Get the HTTP Files variables. Equivalent of $_FILES. + pub fn http_files_vars(&self) -> &ZendHashTable { + self.http_globals[TRACK_VARS_FILES as usize] + .array() + .expect("Type is not a ZendArray") + } +} + /// Executor globals rwlock. /// /// PHP provides no indication if the executor globals are being accessed so /// this is only effective on the Rust side. static GLOBALS_LOCK: RwLock<()> = const_rwlock(()); +static PROCESS_GLOBALS_LOCK: RwLock<()> = const_rwlock(()); /// Wrapper guard that contains a reference to a given type `T`. Dropping a /// guard releases the lock on the relevant rwlock. diff --git a/src/zend/mod.rs b/src/zend/mod.rs index 74547f0..2aabd81 100644 --- a/src/zend/mod.rs +++ b/src/zend/mod.rs @@ -17,6 +17,7 @@ pub use class::ClassEntry; pub use ex::ExecuteData; pub use function::FunctionEntry; pub use globals::ExecutorGlobals; +pub use globals::ProcessGlobals; pub use handlers::ZendObjectHandlers; pub use module::ModuleEntry;