Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions allowed_bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ bind! {
zend_objects_clone_members,
zend_register_bool_constant,
zend_register_double_constant,
zend_register_ini_entries,
zend_ini_entry_def,
zend_register_internal_class_ex,
zend_register_long_constant,
zend_register_string_constant,
Expand Down Expand Up @@ -157,6 +159,10 @@ bind! {
IS_PTR,
MAY_BE_ANY,
MAY_BE_BOOL,
PHP_INI_USER,
PHP_INI_PERDIR,
PHP_INI_SYSTEM,
PHP_INI_ALL,
USING_ZTS,
ZEND_ACC_ABSTRACT,
ZEND_ACC_ANON_CLASS,
Expand Down
36 changes: 36 additions & 0 deletions docsrs_bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ pub const ZEND_MODULE_API_NO: u32 = 20220829;
pub const USING_ZTS: u32 = 0;
pub const MAY_BE_BOOL: u32 = 12;
pub const MAY_BE_ANY: u32 = 1022;
pub const PHP_INI_USER: u32 = 1;
pub const PHP_INI_PERDIR: u32 = 2;
pub const PHP_INI_SYSTEM: u32 = 4;
pub const PHP_INI_ALL: u32 = 7;
pub const CONST_CS: u32 = 0;
pub const CONST_PERSISTENT: u32 = 1;
pub const CONST_NO_FILE_CACHE: u32 = 2;
Expand Down Expand Up @@ -1376,6 +1380,32 @@ extern "C" {
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _zend_ini_entry_def {
pub name: *const ::std::os::raw::c_char,
pub on_modify: ::std::option::Option<
unsafe extern "C" fn(
entry: *mut zend_ini_entry,
new_value: *mut zend_string,
mh_arg1: *mut ::std::os::raw::c_void,
mh_arg2: *mut ::std::os::raw::c_void,
mh_arg3: *mut ::std::os::raw::c_void,
stage: ::std::os::raw::c_int,
) -> ::std::os::raw::c_int,
>,
pub mh_arg1: *mut ::std::os::raw::c_void,
pub mh_arg2: *mut ::std::os::raw::c_void,
pub mh_arg3: *mut ::std::os::raw::c_void,
pub value: *const ::std::os::raw::c_char,
pub displayer: ::std::option::Option<
unsafe extern "C" fn(ini_entry: *mut zend_ini_entry, type_: ::std::os::raw::c_int),
>,
pub value_length: u32,
pub name_length: u16,
pub modifiable: u8,
}
pub type zend_ini_entry_def = _zend_ini_entry_def;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _zend_ini_entry {
pub name: *mut zend_string,
pub on_modify: ::std::option::Option<
Expand All @@ -1401,6 +1431,12 @@ pub struct _zend_ini_entry {
pub orig_modifiable: u8,
pub modified: u8,
}
extern "C" {
pub fn zend_register_ini_entries(
ini_entry: *const zend_ini_entry_def,
module_number: ::std::os::raw::c_int,
) -> zend_result;
}
extern "C" {
pub fn zend_register_bool_constant(
name: *const ::std::os::raw::c_char,
Expand Down
1 change: 1 addition & 0 deletions guide/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@
- [Constants](./macros/constant.md)
- [`ZvalConvert`](./macros/zval_convert.md)
- [Exceptions](./exceptions.md)
- [INI Settings](./ini-settings.md)
48 changes: 48 additions & 0 deletions guide/src/ini-settings.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# INI Settings

Your PHP Extension may want to provide it's own PHP INI settings to configure behaviour. This can be done in the `#[php_startup]` annotated startup function.

## Registering INI Settings

All PHP INI definitions must be registered with PHP to get / set their values via the `php.ini` file or `ini_get() / ini_set()`.


```rust,no_run
# #![cfg_attr(windows, feature(abi_vectorcall))]
# extern crate ext_php_rs;
# use ext_php_rs::prelude::*;
# use ext_php_rs::zend::IniEntryDef;
# use ext_php_rs::flags::IniEntryPermission;

#[php_startup]
pub fn startup_function(ty: i32, module_number: i32) {
let ini_entries: Vec<IniEntryDef> = vec![
IniEntryDef::new(
"my_extension.display_emoji".to_owned(),
"yes".to_owned(),
IniEntryPermission::All,
),
];
IniEntryDef::register(ini_entries, module_number);
}
# fn main() {}
```

## Getting INI Settings

The INI values are stored as part of the `GlobalExecutor`, and can be accessed via the `ini_values()` function. To retrieve the value for a registered INI setting

```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_startup]
pub fn startup_function(ty: i32, module_number: i32) {
// Get all INI values
let ini_values = ExecutorGlobals::get().ini_values(); // HashMap<String, Option<String>>
let my_ini_value = ini_values.get("my_extension.display_emoji"); // Option<Option<String>>
}
# fn main() {}
```
22 changes: 17 additions & 5 deletions src/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ use crate::ffi::{
E_RECOVERABLE_ERROR, E_STRICT, E_USER_DEPRECATED, E_USER_ERROR, E_USER_NOTICE, E_USER_WARNING,
E_WARNING, IS_ARRAY, IS_CALLABLE, IS_CONSTANT_AST, IS_DOUBLE, IS_FALSE, IS_LONG, IS_MIXED,
IS_NULL, IS_OBJECT, IS_PTR, IS_REFERENCE, IS_RESOURCE, IS_STRING, IS_TRUE, IS_TYPE_COLLECTABLE,
IS_TYPE_REFCOUNTED, IS_UNDEF, IS_VOID, ZEND_ACC_ABSTRACT, ZEND_ACC_ANON_CLASS,
ZEND_ACC_CALL_VIA_TRAMPOLINE, ZEND_ACC_CHANGED, ZEND_ACC_CLOSURE, ZEND_ACC_CONSTANTS_UPDATED,
ZEND_ACC_CTOR, ZEND_ACC_DEPRECATED, ZEND_ACC_DONE_PASS_TWO, ZEND_ACC_EARLY_BINDING,
ZEND_ACC_FAKE_CLOSURE, ZEND_ACC_FINAL, ZEND_ACC_GENERATOR, ZEND_ACC_HAS_FINALLY_BLOCK,
ZEND_ACC_HAS_RETURN_TYPE, ZEND_ACC_HAS_TYPE_HINTS, ZEND_ACC_HEAP_RT_CACHE, ZEND_ACC_IMMUTABLE,
IS_TYPE_REFCOUNTED, IS_UNDEF, IS_VOID, PHP_INI_ALL, PHP_INI_PERDIR, PHP_INI_SYSTEM,
PHP_INI_USER, ZEND_ACC_ABSTRACT, ZEND_ACC_ANON_CLASS, ZEND_ACC_CALL_VIA_TRAMPOLINE,
ZEND_ACC_CHANGED, ZEND_ACC_CLOSURE, ZEND_ACC_CONSTANTS_UPDATED, ZEND_ACC_CTOR,
ZEND_ACC_DEPRECATED, ZEND_ACC_DONE_PASS_TWO, ZEND_ACC_EARLY_BINDING, ZEND_ACC_FAKE_CLOSURE,
ZEND_ACC_FINAL, ZEND_ACC_GENERATOR, ZEND_ACC_HAS_FINALLY_BLOCK, ZEND_ACC_HAS_RETURN_TYPE,
ZEND_ACC_HAS_TYPE_HINTS, ZEND_ACC_HEAP_RT_CACHE, ZEND_ACC_IMMUTABLE,
ZEND_ACC_IMPLICIT_ABSTRACT_CLASS, ZEND_ACC_INTERFACE, ZEND_ACC_LINKED, ZEND_ACC_NEARLY_LINKED,
ZEND_ACC_NEVER_CACHE, ZEND_ACC_NO_DYNAMIC_PROPERTIES, ZEND_ACC_PRELOADED, ZEND_ACC_PRIVATE,
ZEND_ACC_PROMOTED, ZEND_ACC_PROTECTED, ZEND_ACC_PUBLIC, ZEND_ACC_RESOLVED_INTERFACES,
Expand Down Expand Up @@ -174,6 +175,16 @@ bitflags! {
}
}

bitflags! {
/// Represents permissions for where a configuration setting may be set.
pub struct IniEntryPermission: u32 {
const User = PHP_INI_USER;
const PerDir = PHP_INI_PERDIR;
const System = PHP_INI_SYSTEM;
const All = PHP_INI_ALL;
}
}

bitflags! {
/// Represents error types when used via php_error_docref for example.
pub struct ErrorType: u32 {
Expand All @@ -194,6 +205,7 @@ bitflags! {
const UserDeprecated = E_USER_DEPRECATED;
}
}

#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
pub enum FunctionType {
Internal,
Expand Down
1 change: 1 addition & 0 deletions src/wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "zend_exceptions.h"
#include "zend_inheritance.h"
#include "zend_interfaces.h"
#include "zend_ini.h"

zend_string *ext_php_rs_zend_string_init(const char *str, size_t len, bool persistent);
void ext_php_rs_zend_string_release(zend_string *zs);
Expand Down
28 changes: 27 additions & 1 deletion src/zend/globals.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
//! Types related to the PHP executor globals.

use std::collections::HashMap;
use std::ops::{Deref, DerefMut};

use parking_lot::{const_rwlock, RwLock, RwLockReadGuard, RwLockWriteGuard};

use crate::boxed::ZBox;
#[cfg(php82)]
use crate::ffi::zend_atomic_bool_store;
use crate::ffi::{_zend_executor_globals, ext_php_rs_executor_globals};
use crate::ffi::{_zend_executor_globals, ext_php_rs_executor_globals, zend_ini_entry};
use crate::types::{ZendHashTable, ZendObject};

/// Stores global variables used in the PHP executor.
Expand Down Expand Up @@ -51,6 +52,31 @@ impl ExecutorGlobals {
unsafe { self.class_table.as_ref() }
}

/// Retrieves the ini values for all ini directives in the current executor
/// context..
pub fn ini_values(&self) -> HashMap<String, Option<String>> {
let hash_table = unsafe { &*self.ini_directives };
let mut ini_hash_map: HashMap<String, Option<String>> = HashMap::new();
for (_index, key, value) in hash_table.iter() {
if let Some(key) = key {
ini_hash_map.insert(key, unsafe {
let ini_entry = &*value.ptr::<zend_ini_entry>().expect("Invalid ini entry");
if ini_entry.value.is_null() {
None
} else {
Some(
(*ini_entry.value)
.as_str()
.expect("Ini value is not a string")
.to_owned(),
)
}
});
}
}
ini_hash_map
}

/// Attempts to retrieve the global constants table.
pub fn constants(&self) -> Option<&ZendHashTable> {
unsafe { self.zend_constants.as_ref() }
Expand Down
57 changes: 57 additions & 0 deletions src/zend/ini_entry_def.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//! Builder for creating inis and methods in PHP.
//! See <https://www.phpinternalsbook.com/php7/extensions_design/ini_settings.html> for details.

use std::{ffi::CString, os::raw::c_char, ptr};

use crate::{ffi::zend_ini_entry_def, ffi::zend_register_ini_entries, flags::IniEntryPermission};

/// A Zend ini entry definition.
///
/// To register ini definitions for extensions, the IniEntryDef builder should be used. Ini
/// entries should be registered in your module's startup_function via `IniEntryDef::register(Vec<IniEntryDef>)`.
pub type IniEntryDef = zend_ini_entry_def;

impl IniEntryDef {
/// Returns an empty ini entry, signifying the end of a ini list.
pub fn new(name: String, default_value: String, permission: IniEntryPermission) -> Self {
let mut template = Self::end();
let name = CString::new(name).expect("Unable to create CString from name");
let value = CString::new(default_value).expect("Unable to create CString from value");
template.name_length = name.as_bytes().len() as _;
template.name = name.into_raw();
template.value_length = value.as_bytes().len() as _;
template.value = value.into_raw();
template.modifiable = IniEntryPermission::PerDir.bits() as _;
template.modifiable = permission.bits() as _;
template
}

/// Returns an empty ini entry def, signifying the end of a ini list.
pub fn end() -> Self {
Self {
name: ptr::null() as *const c_char,
on_modify: None,
mh_arg1: std::ptr::null_mut(),
mh_arg2: std::ptr::null_mut(),
mh_arg3: std::ptr::null_mut(),
value: std::ptr::null_mut(),
displayer: None,
modifiable: 0,
value_length: 0,
name_length: 0,
}
}

/// Converts the ini entry into a raw and pointer, releasing it to the
/// C world.
pub fn into_raw(self) -> *mut Self {
Box::into_raw(Box::new(self))
}

pub fn register(mut entries: Vec<Self>, module_number: i32) {
entries.push(Self::end());
let entries = Box::into_raw(entries.into_boxed_slice()) as *const Self;

unsafe { zend_register_ini_entries(entries, module_number) };
}
}
2 changes: 2 additions & 0 deletions src/zend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ mod ex;
mod function;
mod globals;
mod handlers;
mod ini_entry_def;
mod module;

use crate::{error::Result, ffi::php_printf};
Expand All @@ -18,6 +19,7 @@ pub use ex::ExecuteData;
pub use function::FunctionEntry;
pub use globals::ExecutorGlobals;
pub use handlers::ZendObjectHandlers;
pub use ini_entry_def::IniEntryDef;
pub use module::ModuleEntry;

// Used as the format string for `php_printf`.
Expand Down