diff --git a/allowed_bindings.rs b/allowed_bindings.rs index 8d12aa0..8578480 100644 --- a/allowed_bindings.rs +++ b/allowed_bindings.rs @@ -46,6 +46,7 @@ bind! { // ext_php_rs_is_kown_valid_utf8, // ext_php_rs_set_kown_valid_utf8, object_properties_init, + php_error_docref, php_info_print_table_end, php_info_print_table_header, php_info_print_table_row, @@ -113,6 +114,21 @@ bind! { CONST_DEPRECATED, CONST_NO_FILE_CACHE, CONST_PERSISTENT, + E_ERROR, + E_WARNING, + E_PARSE, + E_NOTICE, + E_CORE_ERROR, + E_CORE_WARNING, + E_COMPILE_ERROR, + E_COMPILE_WARNING, + E_USER_ERROR, + E_USER_WARNING, + E_USER_NOTICE, + E_STRICT, + E_RECOVERABLE_ERROR, + E_DEPRECATED, + E_USER_DEPRECATED, HT_MIN_SIZE, IS_ARRAY, IS_ARRAY_EX, diff --git a/docsrs_bindings.rs b/docsrs_bindings.rs index ce10e9a..22817ac 100644 --- a/docsrs_bindings.rs +++ b/docsrs_bindings.rs @@ -111,6 +111,21 @@ pub const IS_OBJECT_EX: u32 = 776; pub const IS_RESOURCE_EX: u32 = 265; pub const IS_REFERENCE_EX: u32 = 266; pub const IS_CONSTANT_AST_EX: u32 = 267; +pub const E_ERROR: u32 = 1; +pub const E_WARNING: u32 = 2; +pub const E_PARSE: u32 = 4; +pub const E_NOTICE: u32 = 8; +pub const E_CORE_ERROR: u32 = 16; +pub const E_CORE_WARNING: u32 = 32; +pub const E_COMPILE_ERROR: u32 = 64; +pub const E_COMPILE_WARNING: u32 = 128; +pub const E_USER_ERROR: u32 = 256; +pub const E_USER_WARNING: u32 = 512; +pub const E_USER_NOTICE: u32 = 1024; +pub const E_STRICT: u32 = 2048; +pub const E_RECOVERABLE_ERROR: u32 = 4096; +pub const E_DEPRECATED: u32 = 8192; +pub const E_USER_DEPRECATED: u32 = 16384; pub const ZEND_PROPERTY_ISSET: u32 = 0; pub const ZEND_PROPERTY_EXISTS: u32 = 2; pub const ZEND_ACC_PUBLIC: u32 = 1; @@ -1584,6 +1599,14 @@ extern "C" { extern "C" { pub fn php_printf(format: *const ::std::os::raw::c_char, ...) -> usize; } +extern "C" { + pub fn php_error_docref( + docref: *const ::std::os::raw::c_char, + type_: ::std::os::raw::c_int, + format: *const ::std::os::raw::c_char, + ... + ); +} pub type php_stream = _php_stream; pub type php_stream_wrapper = _php_stream_wrapper; pub type php_stream_context = _php_stream_context; @@ -2128,6 +2151,25 @@ extern "C" { extern "C" { pub fn php_info_print_table_end(); } +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct php_file_globals { + pub pclose_ret: ::std::os::raw::c_int, + pub def_chunk_size: usize, + pub auto_detect_line_endings: bool, + pub default_socket_timeout: zend_long, + pub user_agent: *mut ::std::os::raw::c_char, + pub from_address: *mut ::std::os::raw::c_char, + pub user_stream_current_filename: *const ::std::os::raw::c_char, + pub default_context: *mut php_stream_context, + pub stream_wrappers: *mut HashTable, + pub stream_filters: *mut HashTable, + pub wrapper_errors: *mut HashTable, + pub pclose_wait: ::std::os::raw::c_int, +} +extern "C" { + pub static mut file_globals: php_file_globals; +} extern "C" { pub static mut zend_ce_throwable: *mut zend_class_entry; } diff --git a/src/builders/module.rs b/src/builders/module.rs index 6eaaf51..01bc9e4 100644 --- a/src/builders/module.rs +++ b/src/builders/module.rs @@ -126,6 +126,19 @@ impl ModuleBuilder { self } + /// Sets the post request shutdown function for the extension. + /// + /// This function can be useful if you need to do any final cleanup at the + /// very end of a request, after all other resources have been released. For + /// example, if your extension creates any persistent resources that last + /// beyond a single request, you could use this function to clean those up. # Arguments + /// + /// * `func` - The function to be called when shutdown is requested. + pub fn post_deactivate_function(mut self, func: extern "C" fn() -> i32) -> Self { + self.module.post_deactivate_func = Some(func); + self + } + /// Sets the extension information function for the extension. /// /// # Arguments diff --git a/src/error.rs b/src/error.rs index 841228e..441912f 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,11 +1,16 @@ //! Error and result types returned from the library functions. -use std::{error::Error as ErrorTrait, ffi::NulError, fmt::Display}; +use std::{ + error::Error as ErrorTrait, + ffi::{CString, NulError}, + fmt::Display, +}; use crate::{ boxed::ZBox, exception::PhpException, - flags::{ClassFlags, DataType, ZvalTypeFlags}, + ffi::php_error_docref, + flags::{ClassFlags, DataType, ErrorType, ZvalTypeFlags}, types::ZendObject, }; @@ -108,3 +113,17 @@ impl From for PhpException { Self::default(err.to_string()) } } + +/// Trigger an error that is reported in PHP the same way `trigger_error()` is. +/// +/// See specific error type descriptions at . +pub fn php_error(type_: ErrorType, message: &str) { + let c_string = match CString::new(message) { + Ok(string) => string, + Err(_) => { + return; + } + }; + + unsafe { php_error_docref(std::ptr::null(), type_.bits() as _, c_string.as_ptr()) } +} diff --git a/src/flags.rs b/src/flags.rs index 20378e6..2dcdb6a 100644 --- a/src/flags.rs +++ b/src/flags.rs @@ -5,14 +5,16 @@ use bitflags::bitflags; #[cfg(not(php82))] use crate::ffi::ZEND_ACC_REUSE_GET_ITERATOR; use crate::ffi::{ - CONST_CS, CONST_DEPRECATED, CONST_NO_FILE_CACHE, CONST_PERSISTENT, 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, + CONST_CS, CONST_DEPRECATED, CONST_NO_FILE_CACHE, CONST_PERSISTENT, E_COMPILE_ERROR, + E_COMPILE_WARNING, E_CORE_ERROR, E_CORE_WARNING, E_DEPRECATED, E_ERROR, E_NOTICE, E_PARSE, + 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, 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, @@ -171,6 +173,27 @@ bitflags! { } } +bitflags! { + /// Represents error types when used via php_error_docref for example. + pub struct ErrorType: u32 { + const Error = E_ERROR; + const Warning = E_WARNING; + const Parse = E_PARSE; + const Notice = E_NOTICE; + const CoreError = E_CORE_ERROR; + const CoreWarning = E_CORE_WARNING; + const CompileError = E_COMPILE_ERROR; + const CompileWarning = E_COMPILE_WARNING; + const UserError = E_USER_ERROR; + const UserWarning = E_USER_WARNING; + const UserNotice = E_USER_NOTICE; + const Strict = E_STRICT; + const RecoverableError = E_RECOVERABLE_ERROR; + const Deprecated = E_DEPRECATED; + const UserDeprecated = E_USER_DEPRECATED; + } +} + /// Valid data types for PHP. #[repr(C, u8)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] diff --git a/src/zend/globals.rs b/src/zend/globals.rs index b3cdcca..6e9fa94 100644 --- a/src/zend/globals.rs +++ b/src/zend/globals.rs @@ -60,6 +60,11 @@ impl ExecutorGlobals { unsafe { self.class_table.as_ref() } } + /// Attempts to retrieve the global constants table. + pub fn constants(&self) -> Option<&ZendHashTable> { + unsafe { self.zend_constants.as_ref() } + } + /// Attempts to extract the last PHP exception captured by the interpreter. /// Returned inside a [`ZBox`]. ///