Skip to content

Commit f669891

Browse files
committed
Merge remote-tracking branch 'origin/master'
2 parents 253255b + acd3369 commit f669891

File tree

10 files changed

+193
-16
lines changed

10 files changed

+193
-16
lines changed

.github/actions/zts/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM php:8.2-zts
1+
FROM php:8.2-zts-bullseye
22

33
WORKDIR /tmp
44

allowed_bindings.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ bind! {
4646
// ext_php_rs_is_kown_valid_utf8,
4747
// ext_php_rs_set_kown_valid_utf8,
4848
object_properties_init,
49+
php_error_docref,
4950
php_info_print_table_end,
5051
php_info_print_table_header,
5152
php_info_print_table_row,
@@ -115,6 +116,21 @@ bind! {
115116
CONST_DEPRECATED,
116117
CONST_NO_FILE_CACHE,
117118
CONST_PERSISTENT,
119+
E_ERROR,
120+
E_WARNING,
121+
E_PARSE,
122+
E_NOTICE,
123+
E_CORE_ERROR,
124+
E_CORE_WARNING,
125+
E_COMPILE_ERROR,
126+
E_COMPILE_WARNING,
127+
E_USER_ERROR,
128+
E_USER_WARNING,
129+
E_USER_NOTICE,
130+
E_STRICT,
131+
E_RECOVERABLE_ERROR,
132+
E_DEPRECATED,
133+
E_USER_DEPRECATED,
118134
HT_MIN_SIZE,
119135
IS_ARRAY,
120136
IS_ARRAY_EX,
@@ -203,6 +219,9 @@ bind! {
203219
_ZEND_TYPE_NULLABLE_BIT,
204220
ts_rsrc_id,
205221
_ZEND_TYPE_NAME_BIT,
222+
ZEND_INTERNAL_FUNCTION,
223+
ZEND_USER_FUNCTION,
224+
ZEND_EVAL_CODE,
206225
zval_ptr_dtor,
207226
zend_refcounted_h,
208227
zend_is_true,
@@ -229,5 +248,7 @@ bind! {
229248
php_printf,
230249
__zend_malloc,
231250
tsrm_get_ls_cache,
232-
executor_globals_offset
251+
executor_globals_offset,
252+
zend_atomic_bool_store,
253+
zend_interrupt_function
233254
}

crates/cli/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ repository = "https://github.com/davidcole1340/ext-php-rs"
55
homepage = "https://github.com/davidcole1340/ext-php-rs"
66
license = "MIT OR Apache-2.0"
77
keywords = ["php", "ffi", "zend"]
8-
version = "0.1.7"
8+
version = "0.1.8"
99
authors = ["David Cole <david.cole1340@gmail.com>"]
1010
edition = "2018"
1111
categories = ["api-bindings", "command-line-interface"]

docsrs_bindings.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,21 @@ pub const IS_OBJECT_EX: u32 = 776;
3131
pub const IS_RESOURCE_EX: u32 = 265;
3232
pub const IS_REFERENCE_EX: u32 = 266;
3333
pub const IS_CONSTANT_AST_EX: u32 = 267;
34+
pub const E_ERROR: u32 = 1;
35+
pub const E_WARNING: u32 = 2;
36+
pub const E_PARSE: u32 = 4;
37+
pub const E_NOTICE: u32 = 8;
38+
pub const E_CORE_ERROR: u32 = 16;
39+
pub const E_CORE_WARNING: u32 = 32;
40+
pub const E_COMPILE_ERROR: u32 = 64;
41+
pub const E_COMPILE_WARNING: u32 = 128;
42+
pub const E_USER_ERROR: u32 = 256;
43+
pub const E_USER_WARNING: u32 = 512;
44+
pub const E_USER_NOTICE: u32 = 1024;
45+
pub const E_STRICT: u32 = 2048;
46+
pub const E_RECOVERABLE_ERROR: u32 = 4096;
47+
pub const E_DEPRECATED: u32 = 8192;
48+
pub const E_USER_DEPRECATED: u32 = 16384;
3449
pub const ZEND_PROPERTY_ISSET: u32 = 0;
3550
pub const ZEND_PROPERTY_EXISTS: u32 = 2;
3651
pub const ZEND_ACC_PUBLIC: u32 = 1;
@@ -76,6 +91,9 @@ pub const ZEND_ACC_GENERATOR: u32 = 16777216;
7691
pub const ZEND_ACC_DONE_PASS_TWO: u32 = 33554432;
7792
pub const ZEND_ACC_HEAP_RT_CACHE: u32 = 67108864;
7893
pub const ZEND_ACC_STRICT_TYPES: u32 = 2147483648;
94+
pub const ZEND_INTERNAL_FUNCTION: u32 = 1;
95+
pub const ZEND_USER_FUNCTION: u32 = 2;
96+
pub const ZEND_EVAL_CODE: u32 = 4;
7997
pub const ZEND_ISEMPTY: u32 = 1;
8098
pub const _ZEND_SEND_MODE_SHIFT: u32 = 25;
8199
pub const _ZEND_IS_VARIADIC_BIT: u32 = 134217728;
@@ -655,6 +673,10 @@ pub struct _zend_class_entry__bindgen_ty_4__bindgen_ty_2 {
655673
pub builtin_functions: *const _zend_function_entry,
656674
pub module: *mut _zend_module_entry,
657675
}
676+
extern "C" {
677+
pub static mut zend_interrupt_function:
678+
::std::option::Option<unsafe extern "C" fn(execute_data: *mut zend_execute_data)>;
679+
}
658680
extern "C" {
659681
pub static mut zend_standard_class_def: *mut zend_class_entry;
660682
}
@@ -1046,6 +1068,9 @@ pub struct zend_atomic_bool_s {
10461068
pub value: u8,
10471069
}
10481070
pub type zend_atomic_bool = zend_atomic_bool_s;
1071+
extern "C" {
1072+
pub fn zend_atomic_bool_store(obj: *mut zend_atomic_bool, desired: bool);
1073+
}
10491074
#[repr(C)]
10501075
#[derive(Debug, Copy, Clone)]
10511076
pub struct _zend_stack {
@@ -1355,6 +1380,14 @@ extern "C" {
13551380
extern "C" {
13561381
pub fn php_printf(format: *const ::std::os::raw::c_char, ...) -> usize;
13571382
}
1383+
extern "C" {
1384+
pub fn php_error_docref(
1385+
docref: *const ::std::os::raw::c_char,
1386+
type_: ::std::os::raw::c_int,
1387+
format: *const ::std::os::raw::c_char,
1388+
...
1389+
);
1390+
}
13581391
#[repr(C)]
13591392
#[derive(Debug, Copy, Clone)]
13601393
pub struct _zend_ini_entry {

src/builders/module.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,20 @@ impl ModuleBuilder {
126126
self
127127
}
128128

129+
/// Sets the post request shutdown function for the extension.
130+
///
131+
/// This function can be useful if you need to do any final cleanup at the
132+
/// very end of a request, after all other resources have been released. For
133+
/// example, if your extension creates any persistent resources that last
134+
/// beyond a single request, you could use this function to clean those up.
135+
/// # Arguments
136+
///
137+
/// * `func` - The function to be called when shutdown is requested.
138+
pub fn post_deactivate_function(mut self, func: extern "C" fn() -> i32) -> Self {
139+
self.module.post_deactivate_func = Some(func);
140+
self
141+
}
142+
129143
/// Sets the extension information function for the extension.
130144
///
131145
/// # Arguments

src/convert.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,3 +218,13 @@ impl<T: IntoZval + Clone> IntoZvalDyn for T {
218218
Self::TYPE
219219
}
220220
}
221+
222+
impl IntoZvalDyn for Zval {
223+
fn as_zval(&self, _persistent: bool) -> Result<Zval> {
224+
Ok(self.shallow_clone())
225+
}
226+
227+
fn get_type(&self) -> DataType {
228+
self.get_type()
229+
}
230+
}

src/error.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
//! Error and result types returned from the library functions.
22
3-
use std::{error::Error as ErrorTrait, ffi::NulError, fmt::Display};
3+
use std::{
4+
error::Error as ErrorTrait,
5+
ffi::{CString, NulError},
6+
fmt::Display,
7+
};
48

59
use crate::{
610
boxed::ZBox,
711
exception::PhpException,
8-
flags::{ClassFlags, DataType, ZvalTypeFlags},
12+
ffi::php_error_docref,
13+
flags::{ClassFlags, DataType, ErrorType, ZvalTypeFlags},
914
types::ZendObject,
1015
};
1116

@@ -111,3 +116,17 @@ impl From<Error> for PhpException {
111116
Self::default(err.to_string())
112117
}
113118
}
119+
120+
/// Trigger an error that is reported in PHP the same way `trigger_error()` is.
121+
///
122+
/// See specific error type descriptions at <https://www.php.net/manual/en/errorfunc.constants.php>.
123+
pub fn php_error(type_: ErrorType, message: &str) {
124+
let c_string = match CString::new(message) {
125+
Ok(string) => string,
126+
Err(_) => {
127+
return;
128+
}
129+
};
130+
131+
unsafe { php_error_docref(std::ptr::null(), type_.bits() as _, c_string.as_ptr()) }
132+
}

src/flags.rs

Lines changed: 52 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,24 @@ use bitflags::bitflags;
55
#[cfg(not(php82))]
66
use crate::ffi::ZEND_ACC_REUSE_GET_ITERATOR;
77
use crate::ffi::{
8-
CONST_CS, CONST_DEPRECATED, CONST_NO_FILE_CACHE, CONST_PERSISTENT, IS_ARRAY, IS_CALLABLE,
9-
IS_CONSTANT_AST, IS_DOUBLE, IS_FALSE, IS_LONG, IS_MIXED, IS_NULL, IS_OBJECT, IS_PTR,
10-
IS_REFERENCE, IS_RESOURCE, IS_STRING, IS_TRUE, IS_TYPE_COLLECTABLE, IS_TYPE_REFCOUNTED,
11-
IS_UNDEF, IS_VOID, ZEND_ACC_ABSTRACT, ZEND_ACC_ANON_CLASS, ZEND_ACC_CALL_VIA_TRAMPOLINE,
12-
ZEND_ACC_CHANGED, ZEND_ACC_CLOSURE, ZEND_ACC_CONSTANTS_UPDATED, ZEND_ACC_CTOR,
13-
ZEND_ACC_DEPRECATED, ZEND_ACC_DONE_PASS_TWO, ZEND_ACC_EARLY_BINDING, ZEND_ACC_FAKE_CLOSURE,
14-
ZEND_ACC_FINAL, ZEND_ACC_GENERATOR, ZEND_ACC_HAS_FINALLY_BLOCK, ZEND_ACC_HAS_RETURN_TYPE,
15-
ZEND_ACC_HAS_TYPE_HINTS, ZEND_ACC_HEAP_RT_CACHE, ZEND_ACC_IMMUTABLE,
8+
CONST_CS, CONST_DEPRECATED, CONST_NO_FILE_CACHE, CONST_PERSISTENT, E_COMPILE_ERROR,
9+
E_COMPILE_WARNING, E_CORE_ERROR, E_CORE_WARNING, E_DEPRECATED, E_ERROR, E_NOTICE, E_PARSE,
10+
E_RECOVERABLE_ERROR, E_STRICT, E_USER_DEPRECATED, E_USER_ERROR, E_USER_NOTICE, E_USER_WARNING,
11+
E_WARNING, IS_ARRAY, IS_CALLABLE, IS_CONSTANT_AST, IS_DOUBLE, IS_FALSE, IS_LONG, IS_MIXED,
12+
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,
1618
ZEND_ACC_IMPLICIT_ABSTRACT_CLASS, ZEND_ACC_INTERFACE, ZEND_ACC_LINKED, ZEND_ACC_NEARLY_LINKED,
1719
ZEND_ACC_NEVER_CACHE, ZEND_ACC_NO_DYNAMIC_PROPERTIES, ZEND_ACC_PRELOADED, ZEND_ACC_PRIVATE,
1820
ZEND_ACC_PROMOTED, ZEND_ACC_PROTECTED, ZEND_ACC_PUBLIC, ZEND_ACC_RESOLVED_INTERFACES,
1921
ZEND_ACC_RESOLVED_PARENT, ZEND_ACC_RETURN_REFERENCE, ZEND_ACC_STATIC, ZEND_ACC_STRICT_TYPES,
2022
ZEND_ACC_TOP_LEVEL, ZEND_ACC_TRAIT, ZEND_ACC_TRAIT_CLONE, ZEND_ACC_UNRESOLVED_VARIANCE,
21-
ZEND_ACC_USES_THIS, ZEND_ACC_USE_GUARDS, ZEND_ACC_VARIADIC, ZEND_HAS_STATIC_IN_METHODS,
22-
Z_TYPE_FLAGS_SHIFT, _IS_BOOL,
23+
ZEND_ACC_USES_THIS, ZEND_ACC_USE_GUARDS, ZEND_ACC_VARIADIC, ZEND_EVAL_CODE,
24+
ZEND_HAS_STATIC_IN_METHODS, ZEND_INTERNAL_FUNCTION, ZEND_USER_FUNCTION, Z_TYPE_FLAGS_SHIFT,
25+
_IS_BOOL,
2326
};
2427

2528
use std::{convert::TryFrom, fmt::Display};
@@ -171,6 +174,45 @@ bitflags! {
171174
}
172175
}
173176

177+
bitflags! {
178+
/// Represents error types when used via php_error_docref for example.
179+
pub struct ErrorType: u32 {
180+
const Error = E_ERROR;
181+
const Warning = E_WARNING;
182+
const Parse = E_PARSE;
183+
const Notice = E_NOTICE;
184+
const CoreError = E_CORE_ERROR;
185+
const CoreWarning = E_CORE_WARNING;
186+
const CompileError = E_COMPILE_ERROR;
187+
const CompileWarning = E_COMPILE_WARNING;
188+
const UserError = E_USER_ERROR;
189+
const UserWarning = E_USER_WARNING;
190+
const UserNotice = E_USER_NOTICE;
191+
const Strict = E_STRICT;
192+
const RecoverableError = E_RECOVERABLE_ERROR;
193+
const Deprecated = E_DEPRECATED;
194+
const UserDeprecated = E_USER_DEPRECATED;
195+
}
196+
}
197+
#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
198+
pub enum FunctionType {
199+
Internal,
200+
User,
201+
Eval,
202+
}
203+
204+
impl From<u8> for FunctionType {
205+
#[allow(clippy::bad_bit_mask)]
206+
fn from(value: u8) -> Self {
207+
match value as _ {
208+
ZEND_INTERNAL_FUNCTION => Self::Internal,
209+
ZEND_USER_FUNCTION => Self::User,
210+
ZEND_EVAL_CODE => Self::Eval,
211+
_ => panic!("Unknown function type: {}", value),
212+
}
213+
}
214+
}
215+
174216
/// Valid data types for PHP.
175217
#[repr(C, u8)]
176218
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]

src/zend/class.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ impl ClassEntry {
8989
Self::try_find(name.as_str().ok()?)
9090
}
9191
}
92+
93+
pub fn name(&self) -> Option<&str> {
94+
unsafe { self.name.as_ref().and_then(|s| s.as_str().ok()) }
95+
}
9296
}
9397

9498
impl PartialEq for ClassEntry {

src/zend/globals.rs

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ use parking_lot::{const_rwlock, RwLock, RwLockReadGuard, RwLockWriteGuard};
66

77

88
use crate::boxed::ZBox;
9+
#[cfg(php82)]
10+
use crate::ffi::zend_atomic_bool_store;
911
use crate::ffi::{_zend_executor_globals, ext_php_rs_executor_globals};
10-
1112
use crate::types::{ZendHashTable, ZendObject};
1213

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

55+
/// Attempts to retrieve the global constants table.
56+
pub fn constants(&self) -> Option<&ZendHashTable> {
57+
unsafe { self.zend_constants.as_ref() }
58+
}
59+
5460
/// Attempts to extract the last PHP exception captured by the interpreter.
5561
/// Returned inside a [`ZBox`].
5662
///
@@ -66,6 +72,34 @@ impl ExecutorGlobals {
6672
// SAFETY: `as_mut` checks for null.
6773
Some(unsafe { ZBox::from_raw(exception_ptr.as_mut()?) })
6874
}
75+
76+
/// Request an interrupt of the PHP VM. This will call the registered
77+
/// interrupt handler function.
78+
/// set with [`crate::ffi::zend_interrupt_function`].
79+
pub fn request_interrupt(&mut self) {
80+
cfg_if::cfg_if! {
81+
if #[cfg(php82)] {
82+
unsafe {
83+
zend_atomic_bool_store(&mut self.vm_interrupt, true);
84+
}
85+
} else {
86+
self.vm_interrupt = true;
87+
}
88+
}
89+
}
90+
91+
/// Cancel a requested an interrupt of the PHP VM.
92+
pub fn cancel_interrupt(&mut self) {
93+
cfg_if::cfg_if! {
94+
if #[cfg(php82)] {
95+
unsafe {
96+
zend_atomic_bool_store(&mut self.vm_interrupt, false);
97+
}
98+
} else {
99+
self.vm_interrupt = true;
100+
}
101+
}
102+
}
69103
}
70104

71105
/// Executor globals rwlock.

0 commit comments

Comments
 (0)