mirror of
https://github.com/danog/ext-php-rs.git
synced 2024-11-26 20:15:22 +01:00
Merge pull request #225 from davidcole1340/ini-definitions
Support registering ini definitions for modules
This commit is contained in:
commit
eff7b0195f
@ -101,6 +101,8 @@ bind! {
|
|||||||
zend_objects_clone_members,
|
zend_objects_clone_members,
|
||||||
zend_register_bool_constant,
|
zend_register_bool_constant,
|
||||||
zend_register_double_constant,
|
zend_register_double_constant,
|
||||||
|
zend_register_ini_entries,
|
||||||
|
zend_ini_entry_def,
|
||||||
zend_register_internal_class_ex,
|
zend_register_internal_class_ex,
|
||||||
zend_register_long_constant,
|
zend_register_long_constant,
|
||||||
zend_register_string_constant,
|
zend_register_string_constant,
|
||||||
@ -159,6 +161,10 @@ bind! {
|
|||||||
IS_PTR,
|
IS_PTR,
|
||||||
MAY_BE_ANY,
|
MAY_BE_ANY,
|
||||||
MAY_BE_BOOL,
|
MAY_BE_BOOL,
|
||||||
|
PHP_INI_USER,
|
||||||
|
PHP_INI_PERDIR,
|
||||||
|
PHP_INI_SYSTEM,
|
||||||
|
PHP_INI_ALL,
|
||||||
USING_ZTS,
|
USING_ZTS,
|
||||||
ZEND_ACC_ABSTRACT,
|
ZEND_ACC_ABSTRACT,
|
||||||
ZEND_ACC_ANON_CLASS,
|
ZEND_ACC_ANON_CLASS,
|
||||||
|
@ -101,6 +101,10 @@ pub const ZEND_MODULE_API_NO: u32 = 20220829;
|
|||||||
pub const USING_ZTS: u32 = 0;
|
pub const USING_ZTS: u32 = 0;
|
||||||
pub const MAY_BE_BOOL: u32 = 12;
|
pub const MAY_BE_BOOL: u32 = 12;
|
||||||
pub const MAY_BE_ANY: u32 = 1022;
|
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_CS: u32 = 0;
|
||||||
pub const CONST_PERSISTENT: u32 = 1;
|
pub const CONST_PERSISTENT: u32 = 1;
|
||||||
pub const CONST_NO_FILE_CACHE: u32 = 2;
|
pub const CONST_NO_FILE_CACHE: u32 = 2;
|
||||||
@ -1402,6 +1406,32 @@ extern "C" {
|
|||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[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 struct _zend_ini_entry {
|
||||||
pub name: *mut zend_string,
|
pub name: *mut zend_string,
|
||||||
pub on_modify: ::std::option::Option<
|
pub on_modify: ::std::option::Option<
|
||||||
@ -1427,6 +1457,12 @@ pub struct _zend_ini_entry {
|
|||||||
pub orig_modifiable: u8,
|
pub orig_modifiable: u8,
|
||||||
pub modified: 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" {
|
extern "C" {
|
||||||
pub fn zend_register_bool_constant(
|
pub fn zend_register_bool_constant(
|
||||||
name: *const ::std::os::raw::c_char,
|
name: *const ::std::os::raw::c_char,
|
||||||
|
@ -33,3 +33,4 @@
|
|||||||
- [Constants](./macros/constant.md)
|
- [Constants](./macros/constant.md)
|
||||||
- [`ZvalConvert`](./macros/zval_convert.md)
|
- [`ZvalConvert`](./macros/zval_convert.md)
|
||||||
- [Exceptions](./exceptions.md)
|
- [Exceptions](./exceptions.md)
|
||||||
|
- [INI Settings](./ini-settings.md)
|
||||||
|
48
guide/src/ini-settings.md
Normal file
48
guide/src/ini-settings.md
Normal file
@ -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
src/flags.rs
22
src/flags.rs
@ -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_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,
|
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_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,
|
IS_TYPE_REFCOUNTED, IS_UNDEF, IS_VOID, PHP_INI_ALL, PHP_INI_PERDIR, PHP_INI_SYSTEM,
|
||||||
ZEND_ACC_CALL_VIA_TRAMPOLINE, ZEND_ACC_CHANGED, ZEND_ACC_CLOSURE, ZEND_ACC_CONSTANTS_UPDATED,
|
PHP_INI_USER, ZEND_ACC_ABSTRACT, ZEND_ACC_ANON_CLASS, ZEND_ACC_CALL_VIA_TRAMPOLINE,
|
||||||
ZEND_ACC_CTOR, ZEND_ACC_DEPRECATED, ZEND_ACC_DONE_PASS_TWO, ZEND_ACC_EARLY_BINDING,
|
ZEND_ACC_CHANGED, ZEND_ACC_CLOSURE, ZEND_ACC_CONSTANTS_UPDATED, ZEND_ACC_CTOR,
|
||||||
ZEND_ACC_FAKE_CLOSURE, ZEND_ACC_FINAL, ZEND_ACC_GENERATOR, ZEND_ACC_HAS_FINALLY_BLOCK,
|
ZEND_ACC_DEPRECATED, ZEND_ACC_DONE_PASS_TWO, ZEND_ACC_EARLY_BINDING, ZEND_ACC_FAKE_CLOSURE,
|
||||||
ZEND_ACC_HAS_RETURN_TYPE, ZEND_ACC_HAS_TYPE_HINTS, ZEND_ACC_HEAP_RT_CACHE, ZEND_ACC_IMMUTABLE,
|
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_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_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,
|
ZEND_ACC_PROMOTED, ZEND_ACC_PROTECTED, ZEND_ACC_PUBLIC, ZEND_ACC_RESOLVED_INTERFACES,
|
||||||
@ -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! {
|
bitflags! {
|
||||||
/// Represents error types when used via php_error_docref for example.
|
/// Represents error types when used via php_error_docref for example.
|
||||||
pub struct ErrorType: u32 {
|
pub struct ErrorType: u32 {
|
||||||
@ -194,6 +205,7 @@ bitflags! {
|
|||||||
const UserDeprecated = E_USER_DEPRECATED;
|
const UserDeprecated = E_USER_DEPRECATED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
|
#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
|
||||||
pub enum FunctionType {
|
pub enum FunctionType {
|
||||||
Internal,
|
Internal,
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "zend_exceptions.h"
|
#include "zend_exceptions.h"
|
||||||
#include "zend_inheritance.h"
|
#include "zend_inheritance.h"
|
||||||
#include "zend_interfaces.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);
|
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);
|
void ext_php_rs_zend_string_release(zend_string *zs);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
//! Types related to the PHP executor globals.
|
//! Types related to the PHP executor globals.
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
use parking_lot::{const_rwlock, RwLock, RwLockReadGuard, RwLockWriteGuard};
|
use parking_lot::{const_rwlock, RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||||
@ -7,7 +8,7 @@ use parking_lot::{const_rwlock, RwLock, RwLockReadGuard, RwLockWriteGuard};
|
|||||||
use crate::boxed::ZBox;
|
use crate::boxed::ZBox;
|
||||||
#[cfg(php82)]
|
#[cfg(php82)]
|
||||||
use crate::ffi::zend_atomic_bool_store;
|
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};
|
use crate::types::{ZendHashTable, ZendObject};
|
||||||
|
|
||||||
/// Stores global variables used in the PHP executor.
|
/// Stores global variables used in the PHP executor.
|
||||||
@ -51,6 +52,31 @@ impl ExecutorGlobals {
|
|||||||
unsafe { self.class_table.as_ref() }
|
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.
|
/// Attempts to retrieve the global constants table.
|
||||||
pub fn constants(&self) -> Option<&ZendHashTable> {
|
pub fn constants(&self) -> Option<&ZendHashTable> {
|
||||||
unsafe { self.zend_constants.as_ref() }
|
unsafe { self.zend_constants.as_ref() }
|
||||||
|
57
src/zend/ini_entry_def.rs
Normal file
57
src/zend/ini_entry_def.rs
Normal file
@ -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) };
|
||||||
|
}
|
||||||
|
}
|
@ -7,6 +7,7 @@ mod ex;
|
|||||||
mod function;
|
mod function;
|
||||||
mod globals;
|
mod globals;
|
||||||
mod handlers;
|
mod handlers;
|
||||||
|
mod ini_entry_def;
|
||||||
mod module;
|
mod module;
|
||||||
|
|
||||||
use crate::{error::Result, ffi::php_printf};
|
use crate::{error::Result, ffi::php_printf};
|
||||||
@ -19,6 +20,7 @@ pub use function::Function;
|
|||||||
pub use function::FunctionEntry;
|
pub use function::FunctionEntry;
|
||||||
pub use globals::ExecutorGlobals;
|
pub use globals::ExecutorGlobals;
|
||||||
pub use handlers::ZendObjectHandlers;
|
pub use handlers::ZendObjectHandlers;
|
||||||
|
pub use ini_entry_def::IniEntryDef;
|
||||||
pub use module::ModuleEntry;
|
pub use module::ModuleEntry;
|
||||||
|
|
||||||
// Used as the format string for `php_printf`.
|
// Used as the format string for `php_printf`.
|
||||||
|
Loading…
Reference in New Issue
Block a user