From 396c8740e48138039b753c667a60b48637ee13f9 Mon Sep 17 00:00:00 2001 From: Joe Hoyle Date: Tue, 18 Jul 2023 22:38:50 +0200 Subject: [PATCH 1/3] Add support for post shutdown function (#251) --- src/builders/module.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) 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 From a9dffe08f5537be9c3fbb05ca1d93d62a5835c4c Mon Sep 17 00:00:00 2001 From: Joe Hoyle Date: Tue, 18 Jul 2023 22:40:24 +0200 Subject: [PATCH 2/3] Add ability to show PHP warnings (etc) (#231) * Add ability to show PHP warnings (etc) I don't believe there's a way for extensions to trigger PHP notices or warnings currently. This is done using the `php_error_docref` function. I've placed a function in `ext_php_rs::php_error()` however, there might be a better place? * Remove uneeded empty value * Fix url --- allowed_bindings.rs | 16 ++++++++++++++++ docsrs_bindings.rs | 23 +++++++++++++++++++++++ src/error.rs | 23 +++++++++++++++++++++-- src/flags.rs | 39 +++++++++++++++++++++++++++++++-------- 4 files changed, 91 insertions(+), 10 deletions(-) diff --git a/allowed_bindings.rs b/allowed_bindings.rs index 7943f33..b1e2748 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 f4fb348..1888949 100644 --- a/docsrs_bindings.rs +++ b/docsrs_bindings.rs @@ -31,6 +31,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; @@ -1341,6 +1356,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, + ... + ); +} #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct _zend_ini_entry { 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)] From 5d1ffcec05f271d4e7002b7e11064b8e7c994fd8 Mon Sep 17 00:00:00 2001 From: Joe Hoyle Date: Tue, 18 Jul 2023 22:42:40 +0200 Subject: [PATCH 3/3] Add helper to get global constants (#222) ExecutorGlobals::constants() will return a hash map of the available constants. --- src/zend/globals.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/zend/globals.rs b/src/zend/globals.rs index 7ba76c4..0f2cae8 100644 --- a/src/zend/globals.rs +++ b/src/zend/globals.rs @@ -50,6 +50,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`]. ///