diff --git a/guide/src/SUMMARY.md b/guide/src/SUMMARY.md index b3fa7fc6b..626cad84c 100644 --- a/guide/src/SUMMARY.md +++ b/guide/src/SUMMARY.md @@ -36,6 +36,7 @@ - [`Attributes`](./macros/php.md) - [Exceptions](./exceptions.md) - [INI Settings](./ini-settings.md) +- [Superglobals](./superglobals.md) # Advanced Topics diff --git a/guide/src/superglobals.md b/guide/src/superglobals.md new file mode 100644 index 000000000..6c00077cf --- /dev/null +++ b/guide/src/superglobals.md @@ -0,0 +1,333 @@ +# Superglobals + +PHP provides several superglobal arrays that are accessible from any scope. In +ext-php-rs, you can access these superglobals using the `ProcessGlobals`, +`SapiGlobals`, and `ExecutorGlobals` types. + +## Accessing HTTP Superglobals + +The `ProcessGlobals` type provides access to the common HTTP superglobals: + +| Method | PHP Equivalent | +|-----------------------|----------------| +| `http_get_vars()` | `$_GET` | +| `http_post_vars()` | `$_POST` | +| `http_cookie_vars()` | `$_COOKIE` | +| `http_server_vars()` | `$_SERVER` | +| `http_env_vars()` | `$_ENV` | +| `http_files_vars()` | `$_FILES` | +| `http_request_vars()` | `$_REQUEST` | + +### Basic Example + +```rust,no_run +# #![cfg_attr(windows, feature(abi_vectorcall))] +# extern crate ext_php_rs; +use ext_php_rs::prelude::*; +use ext_php_rs::zend::ProcessGlobals; + +#[php_function] +pub fn get_cookie(name: String) -> Option { + ProcessGlobals::get() + .http_cookie_vars() + .get(name.as_str()) + .and_then(|zval| zval.string()) +} + +#[php_function] +pub fn get_query_param(name: String) -> Option { + ProcessGlobals::get() + .http_get_vars() + .get(name.as_str()) + .and_then(|zval| zval.string()) +} + +#[php_function] +pub fn get_post_param(name: String) -> Option { + ProcessGlobals::get() + .http_post_vars() + .get(name.as_str()) + .and_then(|zval| zval.string()) +} +# fn main() {} +``` + +### Accessing `$_SERVER` + +The `$_SERVER` superglobal is lazy-initialized in PHP, so `http_server_vars()` +returns an `Option`: + +```rust,no_run +# #![cfg_attr(windows, feature(abi_vectorcall))] +# extern crate ext_php_rs; +use ext_php_rs::prelude::*; +use ext_php_rs::zend::ProcessGlobals; + +#[php_function] +pub fn get_request_method() -> Option { + ProcessGlobals::get() + .http_server_vars()? + .get("REQUEST_METHOD") + .and_then(|zval| zval.string()) +} + +#[php_function] +pub fn get_remote_addr() -> Option { + ProcessGlobals::get() + .http_server_vars()? + .get("REMOTE_ADDR") + .and_then(|zval| zval.string()) +} + +#[php_function] +pub fn get_user_agent() -> Option { + ProcessGlobals::get() + .http_server_vars()? + .get("HTTP_USER_AGENT") + .and_then(|zval| zval.string()) +} +# fn main() {} +``` + +### Working with `$_FILES` + +```rust,no_run +# #![cfg_attr(windows, feature(abi_vectorcall))] +# extern crate ext_php_rs; +use ext_php_rs::prelude::*; +use ext_php_rs::zend::ProcessGlobals; + +#[php_function] +pub fn get_uploaded_file_name(field: String) -> Option { + let files = ProcessGlobals::get().http_files_vars(); + + // $_FILES structure: $_FILES['field']['name'], ['tmp_name'], ['size'], etc. + files + .get(field.as_str())? + .array()? + .get("name") + .and_then(|zval| zval.string()) +} + +#[php_function] +pub fn get_uploaded_file_tmp_path(field: String) -> Option { + let files = ProcessGlobals::get().http_files_vars(); + + files + .get(field.as_str())? + .array()? + .get("tmp_name") + .and_then(|zval| zval.string()) +} +# fn main() {} +``` + +### Returning Superglobals to PHP + +You can return copies of superglobals back to PHP: + +```rust,no_run +# #![cfg_attr(windows, feature(abi_vectorcall))] +# extern crate ext_php_rs; +use ext_php_rs::prelude::*; +use ext_php_rs::boxed::ZBox; +use ext_php_rs::types::ZendHashTable; +use ext_php_rs::zend::ProcessGlobals; + +#[php_function] +pub fn get_all_cookies() -> ZBox { + ProcessGlobals::get().http_cookie_vars().to_owned() +} + +#[php_function] +pub fn get_all_get_params() -> ZBox { + ProcessGlobals::get().http_get_vars().to_owned() +} + +#[php_function] +pub fn get_server_vars() -> Option> { + Some(ProcessGlobals::get().http_server_vars()?.to_owned()) +} +# fn main() {} +``` + +## SAPI Request Information + +For lower-level request information, use `SapiGlobals`: + +```rust,no_run +# #![cfg_attr(windows, feature(abi_vectorcall))] +# extern crate ext_php_rs; +use ext_php_rs::prelude::*; +use ext_php_rs::zend::SapiGlobals; + +#[php_function] +pub fn get_request_info() -> Vec { + let request_info = SapiGlobals::get().request_info(); + + let mut info = Vec::new(); + + if let Some(method) = request_info.request_method() { + info.push(format!("Method: {}", method)); + } + if let Some(uri) = request_info.request_uri() { + info.push(format!("URI: {}", uri)); + } + if let Some(query) = request_info.query_string() { + info.push(format!("Query: {}", query)); + } + if let Some(content_type) = request_info.content_type() { + info.push(format!("Content-Type: {}", content_type)); + } + info.push(format!("Content-Length: {}", request_info.content_length())); + + info +} +# fn main() {} +``` + +### Available Request Info Methods + +| Method | Description | +|---------------------|-------------------------------| +| `request_method()` | HTTP method (GET, POST, etc.) | +| `request_uri()` | Request URI | +| `query_string()` | Query string | +| `cookie_data()` | Raw cookie data | +| `content_type()` | Content-Type header | +| `content_length()` | Content-Length value | +| `path_translated()` | Translated filesystem path | +| `auth_user()` | HTTP Basic auth username | +| `auth_password()` | HTTP Basic auth password | + +## Accessing Constants + +Use `ExecutorGlobals` to access PHP constants: + +```rust,no_run +# #![cfg_attr(windows, feature(abi_vectorcall))] +# extern crate ext_php_rs; +use ext_php_rs::prelude::*; +use ext_php_rs::zend::ExecutorGlobals; + +#[php_function] +pub fn get_php_version_constant() -> Option { + ExecutorGlobals::get() + .constants() + .get("PHP_VERSION") + .and_then(|zval| zval.string()) +} + +#[php_function] +pub fn constant_exists(name: String) -> bool { + ExecutorGlobals::get() + .constants() + .get(name.as_str()) + .is_some() +} +# fn main() {} +``` + +## Accessing INI Values + +```rust,no_run +# #![cfg_attr(windows, feature(abi_vectorcall))] +# extern crate ext_php_rs; +use ext_php_rs::prelude::*; +use ext_php_rs::zend::ExecutorGlobals; + +#[php_function] +pub fn get_memory_limit() -> Option { + ExecutorGlobals::get() + .ini_values() + .get("memory_limit") + .cloned() + .flatten() +} + +#[php_function] +pub fn get_all_ini_values() -> Vec<(String, String)> { + ExecutorGlobals::get() + .ini_values() + .iter() + .filter_map(|(k, v)| { + v.as_ref().map(|val| (k.clone(), val.clone())) + }) + .collect() +} +# fn main() {} +``` + +## Thread Safety + +All global access methods use guard types that provide thread-safe access: + +- `ProcessGlobals::get()` returns a `GlobalReadGuard` +- `ExecutorGlobals::get()` returns a `GlobalReadGuard` +- `SapiGlobals::get()` returns a `GlobalReadGuard` + +The guard is automatically released when it goes out of scope. For mutable +access (rarely needed), use `get_mut()`: + +```rust,no_run +# #![cfg_attr(windows, feature(abi_vectorcall))] +# extern crate ext_php_rs; +use ext_php_rs::zend::ExecutorGlobals; + +fn example() { + // Read-only access (most common) + let globals = ExecutorGlobals::get(); + // ... use globals ... + // Guard released when `globals` goes out of scope + + // Mutable access (rarely needed) + let mut globals = ExecutorGlobals::get_mut(); + // ... modify globals ... +} +# fn main() {} +``` + +## PHP Example + +```php +