Skip to content

Commit eff7b01

Browse files
authored
Merge pull request #225 from davidcole1340/ini-definitions
Support registering ini definitions for modules
2 parents 2bf8718 + 7b47b46 commit eff7b01

File tree

9 files changed

+195
-6
lines changed

9 files changed

+195
-6
lines changed

allowed_bindings.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ bind! {
101101
zend_objects_clone_members,
102102
zend_register_bool_constant,
103103
zend_register_double_constant,
104+
zend_register_ini_entries,
105+
zend_ini_entry_def,
104106
zend_register_internal_class_ex,
105107
zend_register_long_constant,
106108
zend_register_string_constant,
@@ -159,6 +161,10 @@ bind! {
159161
IS_PTR,
160162
MAY_BE_ANY,
161163
MAY_BE_BOOL,
164+
PHP_INI_USER,
165+
PHP_INI_PERDIR,
166+
PHP_INI_SYSTEM,
167+
PHP_INI_ALL,
162168
USING_ZTS,
163169
ZEND_ACC_ABSTRACT,
164170
ZEND_ACC_ANON_CLASS,

docsrs_bindings.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ pub const ZEND_MODULE_API_NO: u32 = 20220829;
101101
pub const USING_ZTS: u32 = 0;
102102
pub const MAY_BE_BOOL: u32 = 12;
103103
pub const MAY_BE_ANY: u32 = 1022;
104+
pub const PHP_INI_USER: u32 = 1;
105+
pub const PHP_INI_PERDIR: u32 = 2;
106+
pub const PHP_INI_SYSTEM: u32 = 4;
107+
pub const PHP_INI_ALL: u32 = 7;
104108
pub const CONST_CS: u32 = 0;
105109
pub const CONST_PERSISTENT: u32 = 1;
106110
pub const CONST_NO_FILE_CACHE: u32 = 2;
@@ -1402,6 +1406,32 @@ extern "C" {
14021406
}
14031407
#[repr(C)]
14041408
#[derive(Debug, Copy, Clone)]
1409+
pub struct _zend_ini_entry_def {
1410+
pub name: *const ::std::os::raw::c_char,
1411+
pub on_modify: ::std::option::Option<
1412+
unsafe extern "C" fn(
1413+
entry: *mut zend_ini_entry,
1414+
new_value: *mut zend_string,
1415+
mh_arg1: *mut ::std::os::raw::c_void,
1416+
mh_arg2: *mut ::std::os::raw::c_void,
1417+
mh_arg3: *mut ::std::os::raw::c_void,
1418+
stage: ::std::os::raw::c_int,
1419+
) -> ::std::os::raw::c_int,
1420+
>,
1421+
pub mh_arg1: *mut ::std::os::raw::c_void,
1422+
pub mh_arg2: *mut ::std::os::raw::c_void,
1423+
pub mh_arg3: *mut ::std::os::raw::c_void,
1424+
pub value: *const ::std::os::raw::c_char,
1425+
pub displayer: ::std::option::Option<
1426+
unsafe extern "C" fn(ini_entry: *mut zend_ini_entry, type_: ::std::os::raw::c_int),
1427+
>,
1428+
pub value_length: u32,
1429+
pub name_length: u16,
1430+
pub modifiable: u8,
1431+
}
1432+
pub type zend_ini_entry_def = _zend_ini_entry_def;
1433+
#[repr(C)]
1434+
#[derive(Debug, Copy, Clone)]
14051435
pub struct _zend_ini_entry {
14061436
pub name: *mut zend_string,
14071437
pub on_modify: ::std::option::Option<
@@ -1427,6 +1457,12 @@ pub struct _zend_ini_entry {
14271457
pub orig_modifiable: u8,
14281458
pub modified: u8,
14291459
}
1460+
extern "C" {
1461+
pub fn zend_register_ini_entries(
1462+
ini_entry: *const zend_ini_entry_def,
1463+
module_number: ::std::os::raw::c_int,
1464+
) -> zend_result;
1465+
}
14301466
extern "C" {
14311467
pub fn zend_register_bool_constant(
14321468
name: *const ::std::os::raw::c_char,

guide/src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,4 @@
3333
- [Constants](./macros/constant.md)
3434
- [`ZvalConvert`](./macros/zval_convert.md)
3535
- [Exceptions](./exceptions.md)
36+
- [INI Settings](./ini-settings.md)

guide/src/ini-settings.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# INI Settings
2+
3+
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.
4+
5+
## Registering INI Settings
6+
7+
All PHP INI definitions must be registered with PHP to get / set their values via the `php.ini` file or `ini_get() / ini_set()`.
8+
9+
10+
```rust,no_run
11+
# #![cfg_attr(windows, feature(abi_vectorcall))]
12+
# extern crate ext_php_rs;
13+
# use ext_php_rs::prelude::*;
14+
# use ext_php_rs::zend::IniEntryDef;
15+
# use ext_php_rs::flags::IniEntryPermission;
16+
17+
#[php_startup]
18+
pub fn startup_function(ty: i32, module_number: i32) {
19+
let ini_entries: Vec<IniEntryDef> = vec![
20+
IniEntryDef::new(
21+
"my_extension.display_emoji".to_owned(),
22+
"yes".to_owned(),
23+
IniEntryPermission::All,
24+
),
25+
];
26+
IniEntryDef::register(ini_entries, module_number);
27+
}
28+
# fn main() {}
29+
```
30+
31+
## Getting INI Settings
32+
33+
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
34+
35+
```rust,no_run
36+
# #![cfg_attr(windows, feature(abi_vectorcall))]
37+
# extern crate ext_php_rs;
38+
# use ext_php_rs::prelude::*;
39+
# use ext_php_rs::zend::ExecutorGlobals;
40+
41+
#[php_startup]
42+
pub fn startup_function(ty: i32, module_number: i32) {
43+
// Get all INI values
44+
let ini_values = ExecutorGlobals::get().ini_values(); // HashMap<String, Option<String>>
45+
let my_ini_value = ini_values.get("my_extension.display_emoji"); // Option<Option<String>>
46+
}
47+
# fn main() {}
48+
```

src/flags.rs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@ use crate::ffi::{
1010
E_RECOVERABLE_ERROR, E_STRICT, E_USER_DEPRECATED, E_USER_ERROR, E_USER_NOTICE, E_USER_WARNING,
1111
E_WARNING, IS_ARRAY, IS_CALLABLE, IS_CONSTANT_AST, IS_DOUBLE, IS_FALSE, IS_LONG, IS_MIXED,
1212
IS_NULL, IS_OBJECT, IS_PTR, IS_REFERENCE, IS_RESOURCE, IS_STRING, IS_TRUE, IS_TYPE_COLLECTABLE,
13-
IS_TYPE_REFCOUNTED, IS_UNDEF, IS_VOID, ZEND_ACC_ABSTRACT, ZEND_ACC_ANON_CLASS,
14-
ZEND_ACC_CALL_VIA_TRAMPOLINE, ZEND_ACC_CHANGED, ZEND_ACC_CLOSURE, ZEND_ACC_CONSTANTS_UPDATED,
15-
ZEND_ACC_CTOR, ZEND_ACC_DEPRECATED, ZEND_ACC_DONE_PASS_TWO, ZEND_ACC_EARLY_BINDING,
16-
ZEND_ACC_FAKE_CLOSURE, ZEND_ACC_FINAL, ZEND_ACC_GENERATOR, ZEND_ACC_HAS_FINALLY_BLOCK,
17-
ZEND_ACC_HAS_RETURN_TYPE, ZEND_ACC_HAS_TYPE_HINTS, ZEND_ACC_HEAP_RT_CACHE, ZEND_ACC_IMMUTABLE,
13+
IS_TYPE_REFCOUNTED, IS_UNDEF, IS_VOID, PHP_INI_ALL, PHP_INI_PERDIR, PHP_INI_SYSTEM,
14+
PHP_INI_USER, ZEND_ACC_ABSTRACT, ZEND_ACC_ANON_CLASS, ZEND_ACC_CALL_VIA_TRAMPOLINE,
15+
ZEND_ACC_CHANGED, ZEND_ACC_CLOSURE, ZEND_ACC_CONSTANTS_UPDATED, ZEND_ACC_CTOR,
16+
ZEND_ACC_DEPRECATED, ZEND_ACC_DONE_PASS_TWO, ZEND_ACC_EARLY_BINDING, ZEND_ACC_FAKE_CLOSURE,
17+
ZEND_ACC_FINAL, ZEND_ACC_GENERATOR, ZEND_ACC_HAS_FINALLY_BLOCK, ZEND_ACC_HAS_RETURN_TYPE,
18+
ZEND_ACC_HAS_TYPE_HINTS, ZEND_ACC_HEAP_RT_CACHE, ZEND_ACC_IMMUTABLE,
1819
ZEND_ACC_IMPLICIT_ABSTRACT_CLASS, ZEND_ACC_INTERFACE, ZEND_ACC_LINKED, ZEND_ACC_NEARLY_LINKED,
1920
ZEND_ACC_NEVER_CACHE, ZEND_ACC_NO_DYNAMIC_PROPERTIES, ZEND_ACC_PRELOADED, ZEND_ACC_PRIVATE,
2021
ZEND_ACC_PROMOTED, ZEND_ACC_PROTECTED, ZEND_ACC_PUBLIC, ZEND_ACC_RESOLVED_INTERFACES,
@@ -174,6 +175,16 @@ bitflags! {
174175
}
175176
}
176177

178+
bitflags! {
179+
/// Represents permissions for where a configuration setting may be set.
180+
pub struct IniEntryPermission: u32 {
181+
const User = PHP_INI_USER;
182+
const PerDir = PHP_INI_PERDIR;
183+
const System = PHP_INI_SYSTEM;
184+
const All = PHP_INI_ALL;
185+
}
186+
}
187+
177188
bitflags! {
178189
/// Represents error types when used via php_error_docref for example.
179190
pub struct ErrorType: u32 {
@@ -194,6 +205,7 @@ bitflags! {
194205
const UserDeprecated = E_USER_DEPRECATED;
195206
}
196207
}
208+
197209
#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
198210
pub enum FunctionType {
199211
Internal,

src/wrapper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "zend_exceptions.h"
2121
#include "zend_inheritance.h"
2222
#include "zend_interfaces.h"
23+
#include "zend_ini.h"
2324

2425
zend_string *ext_php_rs_zend_string_init(const char *str, size_t len, bool persistent);
2526
void ext_php_rs_zend_string_release(zend_string *zs);

src/zend/globals.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
//! Types related to the PHP executor globals.
22
3+
use std::collections::HashMap;
34
use std::ops::{Deref, DerefMut};
45

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

78
use crate::boxed::ZBox;
89
#[cfg(php82)]
910
use crate::ffi::zend_atomic_bool_store;
10-
use crate::ffi::{_zend_executor_globals, ext_php_rs_executor_globals};
11+
use crate::ffi::{_zend_executor_globals, ext_php_rs_executor_globals, zend_ini_entry};
1112
use crate::types::{ZendHashTable, ZendObject};
1213

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

55+
/// Retrieves the ini values for all ini directives in the current executor
56+
/// context..
57+
pub fn ini_values(&self) -> HashMap<String, Option<String>> {
58+
let hash_table = unsafe { &*self.ini_directives };
59+
let mut ini_hash_map: HashMap<String, Option<String>> = HashMap::new();
60+
for (_index, key, value) in hash_table.iter() {
61+
if let Some(key) = key {
62+
ini_hash_map.insert(key, unsafe {
63+
let ini_entry = &*value.ptr::<zend_ini_entry>().expect("Invalid ini entry");
64+
if ini_entry.value.is_null() {
65+
None
66+
} else {
67+
Some(
68+
(*ini_entry.value)
69+
.as_str()
70+
.expect("Ini value is not a string")
71+
.to_owned(),
72+
)
73+
}
74+
});
75+
}
76+
}
77+
ini_hash_map
78+
}
79+
5480
/// Attempts to retrieve the global constants table.
5581
pub fn constants(&self) -> Option<&ZendHashTable> {
5682
unsafe { self.zend_constants.as_ref() }

src/zend/ini_entry_def.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//! Builder for creating inis and methods in PHP.
2+
//! See <https://www.phpinternalsbook.com/php7/extensions_design/ini_settings.html> for details.
3+
4+
use std::{ffi::CString, os::raw::c_char, ptr};
5+
6+
use crate::{ffi::zend_ini_entry_def, ffi::zend_register_ini_entries, flags::IniEntryPermission};
7+
8+
/// A Zend ini entry definition.
9+
///
10+
/// To register ini definitions for extensions, the IniEntryDef builder should be used. Ini
11+
/// entries should be registered in your module's startup_function via `IniEntryDef::register(Vec<IniEntryDef>)`.
12+
pub type IniEntryDef = zend_ini_entry_def;
13+
14+
impl IniEntryDef {
15+
/// Returns an empty ini entry, signifying the end of a ini list.
16+
pub fn new(name: String, default_value: String, permission: IniEntryPermission) -> Self {
17+
let mut template = Self::end();
18+
let name = CString::new(name).expect("Unable to create CString from name");
19+
let value = CString::new(default_value).expect("Unable to create CString from value");
20+
template.name_length = name.as_bytes().len() as _;
21+
template.name = name.into_raw();
22+
template.value_length = value.as_bytes().len() as _;
23+
template.value = value.into_raw();
24+
template.modifiable = IniEntryPermission::PerDir.bits() as _;
25+
template.modifiable = permission.bits() as _;
26+
template
27+
}
28+
29+
/// Returns an empty ini entry def, signifying the end of a ini list.
30+
pub fn end() -> Self {
31+
Self {
32+
name: ptr::null() as *const c_char,
33+
on_modify: None,
34+
mh_arg1: std::ptr::null_mut(),
35+
mh_arg2: std::ptr::null_mut(),
36+
mh_arg3: std::ptr::null_mut(),
37+
value: std::ptr::null_mut(),
38+
displayer: None,
39+
modifiable: 0,
40+
value_length: 0,
41+
name_length: 0,
42+
}
43+
}
44+
45+
/// Converts the ini entry into a raw and pointer, releasing it to the
46+
/// C world.
47+
pub fn into_raw(self) -> *mut Self {
48+
Box::into_raw(Box::new(self))
49+
}
50+
51+
pub fn register(mut entries: Vec<Self>, module_number: i32) {
52+
entries.push(Self::end());
53+
let entries = Box::into_raw(entries.into_boxed_slice()) as *const Self;
54+
55+
unsafe { zend_register_ini_entries(entries, module_number) };
56+
}
57+
}

src/zend/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ mod ex;
77
mod function;
88
mod globals;
99
mod handlers;
10+
mod ini_entry_def;
1011
mod module;
1112

1213
use crate::{error::Result, ffi::php_printf};
@@ -19,6 +20,7 @@ pub use function::Function;
1920
pub use function::FunctionEntry;
2021
pub use globals::ExecutorGlobals;
2122
pub use handlers::ZendObjectHandlers;
23+
pub use ini_entry_def::IniEntryDef;
2224
pub use module::ModuleEntry;
2325

2426
// Used as the format string for `php_printf`.

0 commit comments

Comments
 (0)