diff --git a/allowed_bindings.rs b/allowed_bindings.rs index 190f31ea4..a317f4d82 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, @@ -225,8 +241,28 @@ bind! { gc_possible_root, ZEND_ACC_NOT_SERIALIZABLE, executor_globals, + php_core_globals, + core_globals, + sapi_globals_struct, + sapi_globals, php_printf, __zend_malloc, tsrm_get_ls_cache, - executor_globals_offset + executor_globals_offset, + core_globals_offset, + sapi_globals_offset, + php_file_globals, + file_globals, + TRACK_VARS_POST, + TRACK_VARS_GET, + TRACK_VARS_COOKIE, + TRACK_VARS_SERVER, + TRACK_VARS_ENV, + TRACK_VARS_FILES, + TRACK_VARS_REQUEST, + sapi_request_info, + sapi_header_struct, + zend_is_auto_global, + zend_llist_get_next_ex, + zend_llist_get_prev_ex } diff --git a/docsrs_bindings.rs b/docsrs_bindings.rs index 960e234f4..b67901595 100644 --- a/docsrs_bindings.rs +++ b/docsrs_bindings.rs @@ -1,5 +1,85 @@ /* automatically generated by rust-bindgen 0.65.1 */ +#[repr(C)] +#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct __BindgenBitfieldUnit { + storage: Storage, +} +impl __BindgenBitfieldUnit { + #[inline] + pub const fn new(storage: Storage) -> Self { + Self { storage } + } +} +impl __BindgenBitfieldUnit +where + Storage: AsRef<[u8]> + AsMut<[u8]>, +{ + #[inline] + pub fn get_bit(&self, index: usize) -> bool { + debug_assert!(index / 8 < self.storage.as_ref().len()); + let byte_index = index / 8; + let byte = self.storage.as_ref()[byte_index]; + let bit_index = if cfg!(target_endian = "big") { + 7 - (index % 8) + } else { + index % 8 + }; + let mask = 1 << bit_index; + byte & mask == mask + } + #[inline] + pub fn set_bit(&mut self, index: usize, val: bool) { + debug_assert!(index / 8 < self.storage.as_ref().len()); + let byte_index = index / 8; + let byte = &mut self.storage.as_mut()[byte_index]; + let bit_index = if cfg!(target_endian = "big") { + 7 - (index % 8) + } else { + index % 8 + }; + let mask = 1 << bit_index; + if val { + *byte |= mask; + } else { + *byte &= !mask; + } + } + #[inline] + pub fn get(&self, bit_offset: usize, bit_width: u8) -> u64 { + debug_assert!(bit_width <= 64); + debug_assert!(bit_offset / 8 < self.storage.as_ref().len()); + debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len()); + let mut val = 0; + for i in 0..(bit_width as usize) { + if self.get_bit(i + bit_offset) { + let index = if cfg!(target_endian = "big") { + bit_width as usize - 1 - i + } else { + i + }; + val |= 1 << index; + } + } + val + } + #[inline] + pub fn set(&mut self, bit_offset: usize, bit_width: u8, val: u64) { + debug_assert!(bit_width <= 64); + debug_assert!(bit_offset / 8 < self.storage.as_ref().len()); + debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len()); + for i in 0..(bit_width as usize) { + let mask = 1 << i; + let val_bit_is_set = val & mask == mask; + let index = if cfg!(target_endian = "big") { + bit_width as usize - 1 - i + } else { + i + }; + self.set_bit(index + bit_offset, val_bit_is_set); + } + } +} pub const ZEND_DEBUG: u32 = 1; pub const _ZEND_TYPE_NAME_BIT: u32 = 16777216; pub const _ZEND_TYPE_NULLABLE_BIT: u32 = 2; @@ -32,6 +112,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; @@ -84,12 +179,105 @@ pub const ZEND_MODULE_API_NO: u32 = 20220829; pub const USING_ZTS: u32 = 0; pub const MAY_BE_BOOL: u32 = 12; pub const MAY_BE_ANY: u32 = 1022; +pub const TRACK_VARS_POST: u32 = 0; +pub const TRACK_VARS_GET: u32 = 1; +pub const TRACK_VARS_COOKIE: u32 = 2; +pub const TRACK_VARS_SERVER: u32 = 3; +pub const TRACK_VARS_ENV: u32 = 4; +pub const TRACK_VARS_FILES: u32 = 5; +pub const TRACK_VARS_REQUEST: u32 = 6; pub const CONST_CS: u32 = 0; pub const CONST_PERSISTENT: u32 = 1; pub const CONST_NO_FILE_CACHE: u32 = 2; pub const CONST_DEPRECATED: u32 = 4; +pub type __uint16_t = ::std::os::raw::c_ushort; +pub type __int32_t = ::std::os::raw::c_int; +pub type __uint32_t = ::std::os::raw::c_uint; +pub type __int64_t = ::std::os::raw::c_longlong; +pub type __uint64_t = ::std::os::raw::c_ulonglong; +pub type __darwin_time_t = ::std::os::raw::c_long; +pub type __darwin_blkcnt_t = __int64_t; +pub type __darwin_blksize_t = __int32_t; +pub type __darwin_dev_t = __int32_t; +pub type __darwin_gid_t = __uint32_t; +pub type __darwin_ino64_t = __uint64_t; +pub type __darwin_mode_t = __uint16_t; +pub type __darwin_off_t = __int64_t; +pub type __darwin_uid_t = __uint32_t; +pub type uid_t = __darwin_uid_t; +pub type dev_t = __darwin_dev_t; +pub type mode_t = __darwin_mode_t; +pub type blkcnt_t = __darwin_blkcnt_t; +pub type blksize_t = __darwin_blksize_t; +pub type gid_t = __darwin_gid_t; +pub type nlink_t = __uint16_t; +pub type off_t = __darwin_off_t; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct timespec { + pub tv_sec: __darwin_time_t, + pub tv_nsec: ::std::os::raw::c_long, +} +pub type fpos_t = __darwin_off_t; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __sbuf { + pub _base: *mut ::std::os::raw::c_uchar, + pub _size: ::std::os::raw::c_int, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __sFILEX { + _unused: [u8; 0], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __sFILE { + pub _p: *mut ::std::os::raw::c_uchar, + pub _r: ::std::os::raw::c_int, + pub _w: ::std::os::raw::c_int, + pub _flags: ::std::os::raw::c_short, + pub _file: ::std::os::raw::c_short, + pub _bf: __sbuf, + pub _lbfsize: ::std::os::raw::c_int, + pub _cookie: *mut ::std::os::raw::c_void, + pub _close: ::std::option::Option< + unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void) -> ::std::os::raw::c_int, + >, + pub _read: ::std::option::Option< + unsafe extern "C" fn( + arg1: *mut ::std::os::raw::c_void, + arg2: *mut ::std::os::raw::c_char, + arg3: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + >, + pub _seek: ::std::option::Option< + unsafe extern "C" fn( + arg1: *mut ::std::os::raw::c_void, + arg2: fpos_t, + arg3: ::std::os::raw::c_int, + ) -> fpos_t, + >, + pub _write: ::std::option::Option< + unsafe extern "C" fn( + arg1: *mut ::std::os::raw::c_void, + arg2: *const ::std::os::raw::c_char, + arg3: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + >, + pub _ub: __sbuf, + pub _extra: *mut __sFILEX, + pub _ur: ::std::os::raw::c_int, + pub _ubuf: [::std::os::raw::c_uchar; 3usize], + pub _nbuf: [::std::os::raw::c_uchar; 1usize], + pub _lb: __sbuf, + pub _blksize: ::std::os::raw::c_int, + pub _offset: fpos_t, +} +pub type FILE = __sFILE; pub type zend_long = i64; pub type zend_ulong = u64; +pub type zend_off_t = i64; pub type zend_uchar = ::std::os::raw::c_uchar; pub const ZEND_RESULT_CODE_SUCCESS: ZEND_RESULT_CODE = 0; pub const ZEND_RESULT_CODE_FAILURE: ZEND_RESULT_CODE = -1; @@ -306,6 +494,41 @@ extern "C" { extern "C" { pub fn __zend_malloc(len: usize) -> *mut ::std::os::raw::c_void; } +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _zend_llist_element { + pub next: *mut _zend_llist_element, + pub prev: *mut _zend_llist_element, + pub data: [::std::os::raw::c_char; 1usize], +} +pub type zend_llist_element = _zend_llist_element; +pub type llist_dtor_func_t = + ::std::option::Option; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _zend_llist { + pub head: *mut zend_llist_element, + pub tail: *mut zend_llist_element, + pub count: usize, + pub size: usize, + pub dtor: llist_dtor_func_t, + pub persistent: ::std::os::raw::c_uchar, + pub traverse_ptr: *mut zend_llist_element, +} +pub type zend_llist = _zend_llist; +pub type zend_llist_position = *mut zend_llist_element; +extern "C" { + pub fn zend_llist_get_next_ex( + l: *mut zend_llist, + pos: *mut zend_llist_position, + ) -> *mut ::std::os::raw::c_void; +} +extern "C" { + pub fn zend_llist_get_prev_ex( + l: *mut zend_llist, + pos: *mut zend_llist_position, + ) -> *mut ::std::os::raw::c_void; +} pub type zend_string_init_interned_func_t = ::std::option::Option< unsafe extern "C" fn( str_: *const ::std::os::raw::c_char, @@ -456,6 +679,29 @@ pub struct _zend_class_arrayaccess_funcs { pub type zend_class_arrayaccess_funcs = _zend_class_arrayaccess_funcs; #[repr(C)] #[derive(Debug, Copy, Clone)] +pub struct stat { + pub st_dev: dev_t, + pub st_mode: mode_t, + pub st_nlink: nlink_t, + pub st_ino: __darwin_ino64_t, + pub st_uid: uid_t, + pub st_gid: gid_t, + pub st_rdev: dev_t, + pub st_atimespec: timespec, + pub st_mtimespec: timespec, + pub st_ctimespec: timespec, + pub st_birthtimespec: timespec, + pub st_size: off_t, + pub st_blocks: blkcnt_t, + pub st_blksize: blksize_t, + pub st_flags: __uint32_t, + pub st_gen: __uint32_t, + pub st_lspare: __int32_t, + pub st_qspare: [__int64_t; 2usize], +} +pub type zend_stat_t = stat; +#[repr(C)] +#[derive(Debug, Copy, Clone)] pub struct _zend_serialize_data { _unused: [u8; 0], } @@ -1165,6 +1411,9 @@ pub struct _zend_executor_globals { pub lineno_override: zend_long, pub reserved: [*mut ::std::os::raw::c_void; 6usize], } +extern "C" { + pub fn zend_is_auto_global(name: *mut zend_string) -> bool; +} pub type zend_module_entry = _zend_module_entry; #[repr(C)] #[derive(Debug, Copy, Clone)] @@ -1248,6 +1497,15 @@ pub struct _zend_function_entry { pub flags: u32, } pub type zend_function_entry = _zend_function_entry; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _zend_fcall_info_cache { + pub function_handler: *mut zend_function, + pub calling_scope: *mut zend_class_entry, + pub called_scope: *mut zend_class_entry, + pub object: *mut zend_object, +} +pub type zend_fcall_info_cache = _zend_fcall_info_cache; extern "C" { pub fn zend_register_internal_class_ex( class_entry: *mut zend_class_entry, @@ -1342,6 +1600,483 @@ 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; +pub type php_stream_filter = _php_stream_filter; +pub type php_stream_notification_func = ::std::option::Option< + unsafe extern "C" fn( + context: *mut php_stream_context, + notifycode: ::std::os::raw::c_int, + severity: ::std::os::raw::c_int, + xmsg: *mut ::std::os::raw::c_char, + xcode: ::std::os::raw::c_int, + bytes_sofar: usize, + bytes_max: usize, + ptr: *mut ::std::os::raw::c_void, + ), +>; +pub type php_stream_notifier = _php_stream_notifier; +#[repr(C)] +pub struct _php_stream_notifier { + pub func: php_stream_notification_func, + pub dtor: ::std::option::Option, + pub ptr: zval, + pub mask: ::std::os::raw::c_int, + pub progress: usize, + pub progress_max: usize, +} +#[repr(C)] +pub struct _php_stream_context { + pub notifier: *mut php_stream_notifier, + pub options: zval, + pub res: *mut zend_resource, +} +pub type php_stream_bucket = _php_stream_bucket; +pub type php_stream_bucket_brigade = _php_stream_bucket_brigade; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _php_stream_bucket { + pub next: *mut php_stream_bucket, + pub prev: *mut php_stream_bucket, + pub brigade: *mut php_stream_bucket_brigade, + pub buf: *mut ::std::os::raw::c_char, + pub buflen: usize, + pub own_buf: u8, + pub is_persistent: u8, + pub refcount: ::std::os::raw::c_int, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _php_stream_bucket_brigade { + pub head: *mut php_stream_bucket, + pub tail: *mut php_stream_bucket, +} +pub const php_stream_filter_status_t_PSFS_ERR_FATAL: php_stream_filter_status_t = 0; +pub const php_stream_filter_status_t_PSFS_FEED_ME: php_stream_filter_status_t = 1; +pub const php_stream_filter_status_t_PSFS_PASS_ON: php_stream_filter_status_t = 2; +pub type php_stream_filter_status_t = ::std::os::raw::c_uint; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _php_stream_filter_ops { + pub filter: ::std::option::Option< + unsafe extern "C" fn( + stream: *mut php_stream, + thisfilter: *mut php_stream_filter, + buckets_in: *mut php_stream_bucket_brigade, + buckets_out: *mut php_stream_bucket_brigade, + bytes_consumed: *mut usize, + flags: ::std::os::raw::c_int, + ) -> php_stream_filter_status_t, + >, + pub dtor: ::std::option::Option, + pub label: *const ::std::os::raw::c_char, +} +pub type php_stream_filter_ops = _php_stream_filter_ops; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _php_stream_filter_chain { + pub head: *mut php_stream_filter, + pub tail: *mut php_stream_filter, + pub stream: *mut php_stream, +} +pub type php_stream_filter_chain = _php_stream_filter_chain; +#[repr(C)] +pub struct _php_stream_filter { + pub fops: *const php_stream_filter_ops, + pub abstract_: zval, + pub next: *mut php_stream_filter, + pub prev: *mut php_stream_filter, + pub is_persistent: ::std::os::raw::c_int, + pub chain: *mut php_stream_filter_chain, + pub buffer: php_stream_bucket_brigade, + pub res: *mut zend_resource, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _php_stream_statbuf { + pub sb: zend_stat_t, +} +pub type php_stream_statbuf = _php_stream_statbuf; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _php_stream_ops { + pub write: ::std::option::Option< + unsafe extern "C" fn( + stream: *mut php_stream, + buf: *const ::std::os::raw::c_char, + count: usize, + ) -> isize, + >, + pub read: ::std::option::Option< + unsafe extern "C" fn( + stream: *mut php_stream, + buf: *mut ::std::os::raw::c_char, + count: usize, + ) -> isize, + >, + pub close: ::std::option::Option< + unsafe extern "C" fn( + stream: *mut php_stream, + close_handle: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + >, + pub flush: ::std::option::Option< + unsafe extern "C" fn(stream: *mut php_stream) -> ::std::os::raw::c_int, + >, + pub label: *const ::std::os::raw::c_char, + pub seek: ::std::option::Option< + unsafe extern "C" fn( + stream: *mut php_stream, + offset: zend_off_t, + whence: ::std::os::raw::c_int, + newoffset: *mut zend_off_t, + ) -> ::std::os::raw::c_int, + >, + pub cast: ::std::option::Option< + unsafe extern "C" fn( + stream: *mut php_stream, + castas: ::std::os::raw::c_int, + ret: *mut *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int, + >, + pub stat: ::std::option::Option< + unsafe extern "C" fn( + stream: *mut php_stream, + ssb: *mut php_stream_statbuf, + ) -> ::std::os::raw::c_int, + >, + pub set_option: ::std::option::Option< + unsafe extern "C" fn( + stream: *mut php_stream, + option: ::std::os::raw::c_int, + value: ::std::os::raw::c_int, + ptrparam: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int, + >, +} +pub type php_stream_ops = _php_stream_ops; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _php_stream_wrapper_ops { + pub stream_opener: ::std::option::Option< + unsafe extern "C" fn( + wrapper: *mut php_stream_wrapper, + filename: *const ::std::os::raw::c_char, + mode: *const ::std::os::raw::c_char, + options: ::std::os::raw::c_int, + opened_path: *mut *mut zend_string, + context: *mut php_stream_context, + __php_stream_call_depth: ::std::os::raw::c_int, + __zend_filename: *const ::std::os::raw::c_char, + __zend_lineno: u32, + __zend_orig_filename: *const ::std::os::raw::c_char, + __zend_orig_lineno: u32, + ) -> *mut php_stream, + >, + pub stream_closer: ::std::option::Option< + unsafe extern "C" fn( + wrapper: *mut php_stream_wrapper, + stream: *mut php_stream, + ) -> ::std::os::raw::c_int, + >, + pub stream_stat: ::std::option::Option< + unsafe extern "C" fn( + wrapper: *mut php_stream_wrapper, + stream: *mut php_stream, + ssb: *mut php_stream_statbuf, + ) -> ::std::os::raw::c_int, + >, + pub url_stat: ::std::option::Option< + unsafe extern "C" fn( + wrapper: *mut php_stream_wrapper, + url: *const ::std::os::raw::c_char, + flags: ::std::os::raw::c_int, + ssb: *mut php_stream_statbuf, + context: *mut php_stream_context, + ) -> ::std::os::raw::c_int, + >, + pub dir_opener: ::std::option::Option< + unsafe extern "C" fn( + wrapper: *mut php_stream_wrapper, + filename: *const ::std::os::raw::c_char, + mode: *const ::std::os::raw::c_char, + options: ::std::os::raw::c_int, + opened_path: *mut *mut zend_string, + context: *mut php_stream_context, + __php_stream_call_depth: ::std::os::raw::c_int, + __zend_filename: *const ::std::os::raw::c_char, + __zend_lineno: u32, + __zend_orig_filename: *const ::std::os::raw::c_char, + __zend_orig_lineno: u32, + ) -> *mut php_stream, + >, + pub label: *const ::std::os::raw::c_char, + pub unlink: ::std::option::Option< + unsafe extern "C" fn( + wrapper: *mut php_stream_wrapper, + url: *const ::std::os::raw::c_char, + options: ::std::os::raw::c_int, + context: *mut php_stream_context, + ) -> ::std::os::raw::c_int, + >, + pub rename: ::std::option::Option< + unsafe extern "C" fn( + wrapper: *mut php_stream_wrapper, + url_from: *const ::std::os::raw::c_char, + url_to: *const ::std::os::raw::c_char, + options: ::std::os::raw::c_int, + context: *mut php_stream_context, + ) -> ::std::os::raw::c_int, + >, + pub stream_mkdir: ::std::option::Option< + unsafe extern "C" fn( + wrapper: *mut php_stream_wrapper, + url: *const ::std::os::raw::c_char, + mode: ::std::os::raw::c_int, + options: ::std::os::raw::c_int, + context: *mut php_stream_context, + ) -> ::std::os::raw::c_int, + >, + pub stream_rmdir: ::std::option::Option< + unsafe extern "C" fn( + wrapper: *mut php_stream_wrapper, + url: *const ::std::os::raw::c_char, + options: ::std::os::raw::c_int, + context: *mut php_stream_context, + ) -> ::std::os::raw::c_int, + >, + pub stream_metadata: ::std::option::Option< + unsafe extern "C" fn( + wrapper: *mut php_stream_wrapper, + url: *const ::std::os::raw::c_char, + options: ::std::os::raw::c_int, + value: *mut ::std::os::raw::c_void, + context: *mut php_stream_context, + ) -> ::std::os::raw::c_int, + >, +} +pub type php_stream_wrapper_ops = _php_stream_wrapper_ops; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _php_stream_wrapper { + pub wops: *const php_stream_wrapper_ops, + pub abstract_: *mut ::std::os::raw::c_void, + pub is_url: ::std::os::raw::c_int, +} +#[repr(C)] +pub struct _php_stream { + pub ops: *const php_stream_ops, + pub abstract_: *mut ::std::os::raw::c_void, + pub readfilters: php_stream_filter_chain, + pub writefilters: php_stream_filter_chain, + pub wrapper: *mut php_stream_wrapper, + pub wrapperthis: *mut ::std::os::raw::c_void, + pub wrapperdata: zval, + pub _bitfield_align_1: [u8; 0], + pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, + pub mode: [::std::os::raw::c_char; 16usize], + pub flags: u32, + pub res: *mut zend_resource, + pub stdiocast: *mut FILE, + pub orig_path: *mut ::std::os::raw::c_char, + pub ctx: *mut zend_resource, + pub position: zend_off_t, + pub readbuf: *mut ::std::os::raw::c_uchar, + pub readbuflen: usize, + pub readpos: zend_off_t, + pub writepos: zend_off_t, + pub chunk_size: usize, + pub open_filename: *const ::std::os::raw::c_char, + pub open_lineno: u32, + pub enclosing_stream: *mut _php_stream, +} +impl _php_stream { + #[inline] + pub fn is_persistent(&self) -> u8 { + unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 1u8) as u8) } + } + #[inline] + pub fn set_is_persistent(&mut self, val: u8) { + unsafe { + let val: u8 = ::std::mem::transmute(val); + self._bitfield_1.set(0usize, 1u8, val as u64) + } + } + #[inline] + pub fn in_free(&self) -> u8 { + unsafe { ::std::mem::transmute(self._bitfield_1.get(1usize, 2u8) as u8) } + } + #[inline] + pub fn set_in_free(&mut self, val: u8) { + unsafe { + let val: u8 = ::std::mem::transmute(val); + self._bitfield_1.set(1usize, 2u8, val as u64) + } + } + #[inline] + pub fn eof(&self) -> u8 { + unsafe { ::std::mem::transmute(self._bitfield_1.get(3usize, 1u8) as u8) } + } + #[inline] + pub fn set_eof(&mut self, val: u8) { + unsafe { + let val: u8 = ::std::mem::transmute(val); + self._bitfield_1.set(3usize, 1u8, val as u64) + } + } + #[inline] + pub fn __exposed(&self) -> u8 { + unsafe { ::std::mem::transmute(self._bitfield_1.get(4usize, 1u8) as u8) } + } + #[inline] + pub fn set___exposed(&mut self, val: u8) { + unsafe { + let val: u8 = ::std::mem::transmute(val); + self._bitfield_1.set(4usize, 1u8, val as u64) + } + } + #[inline] + pub fn fclose_stdiocast(&self) -> u8 { + unsafe { ::std::mem::transmute(self._bitfield_1.get(5usize, 2u8) as u8) } + } + #[inline] + pub fn set_fclose_stdiocast(&mut self, val: u8) { + unsafe { + let val: u8 = ::std::mem::transmute(val); + self._bitfield_1.set(5usize, 2u8, val as u64) + } + } + #[inline] + pub fn new_bitfield_1( + is_persistent: u8, + in_free: u8, + eof: u8, + __exposed: u8, + fclose_stdiocast: u8, + ) -> __BindgenBitfieldUnit<[u8; 1usize]> { + let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 1usize]> = Default::default(); + __bindgen_bitfield_unit.set(0usize, 1u8, { + let is_persistent: u8 = unsafe { ::std::mem::transmute(is_persistent) }; + is_persistent as u64 + }); + __bindgen_bitfield_unit.set(1usize, 2u8, { + let in_free: u8 = unsafe { ::std::mem::transmute(in_free) }; + in_free as u64 + }); + __bindgen_bitfield_unit.set(3usize, 1u8, { + let eof: u8 = unsafe { ::std::mem::transmute(eof) }; + eof as u64 + }); + __bindgen_bitfield_unit.set(4usize, 1u8, { + let __exposed: u8 = unsafe { ::std::mem::transmute(__exposed) }; + __exposed as u64 + }); + __bindgen_bitfield_unit.set(5usize, 2u8, { + let fclose_stdiocast: u8 = unsafe { ::std::mem::transmute(fclose_stdiocast) }; + fclose_stdiocast as u64 + }); + __bindgen_bitfield_unit + } +} +pub type php_core_globals = _php_core_globals; +#[repr(C)] +pub struct _php_core_globals { + pub implicit_flush: bool, + pub output_buffering: zend_long, + pub enable_dl: bool, + pub output_handler: *mut ::std::os::raw::c_char, + pub unserialize_callback_func: *mut ::std::os::raw::c_char, + pub serialize_precision: zend_long, + pub memory_limit: zend_long, + pub max_input_time: zend_long, + pub display_errors: zend_uchar, + pub display_startup_errors: bool, + pub log_errors: bool, + pub ignore_repeated_errors: bool, + pub ignore_repeated_source: bool, + pub report_memleaks: bool, + pub error_log: *mut ::std::os::raw::c_char, + pub doc_root: *mut ::std::os::raw::c_char, + pub user_dir: *mut ::std::os::raw::c_char, + pub include_path: *mut ::std::os::raw::c_char, + pub open_basedir: *mut ::std::os::raw::c_char, + pub extension_dir: *mut ::std::os::raw::c_char, + pub php_binary: *mut ::std::os::raw::c_char, + pub sys_temp_dir: *mut ::std::os::raw::c_char, + pub upload_tmp_dir: *mut ::std::os::raw::c_char, + pub upload_max_filesize: zend_long, + pub error_append_string: *mut ::std::os::raw::c_char, + pub error_prepend_string: *mut ::std::os::raw::c_char, + pub auto_prepend_file: *mut ::std::os::raw::c_char, + pub auto_append_file: *mut ::std::os::raw::c_char, + pub input_encoding: *mut ::std::os::raw::c_char, + pub internal_encoding: *mut ::std::os::raw::c_char, + pub output_encoding: *mut ::std::os::raw::c_char, + pub arg_separator: arg_separators, + pub variables_order: *mut ::std::os::raw::c_char, + pub rfc1867_protected_variables: HashTable, + pub connection_status: ::std::os::raw::c_short, + pub ignore_user_abort: bool, + pub header_is_being_sent: ::std::os::raw::c_uchar, + pub tick_functions: zend_llist, + pub http_globals: [zval; 6usize], + pub expose_php: bool, + pub register_argc_argv: bool, + pub auto_globals_jit: bool, + pub docref_root: *mut ::std::os::raw::c_char, + pub docref_ext: *mut ::std::os::raw::c_char, + pub html_errors: bool, + pub xmlrpc_errors: bool, + pub xmlrpc_error_number: zend_long, + pub activated_auto_globals: [bool; 8usize], + pub modules_activated: bool, + pub file_uploads: bool, + pub during_request_startup: bool, + pub allow_url_fopen: bool, + pub enable_post_data_reading: bool, + pub report_zend_debug: bool, + pub last_error_type: ::std::os::raw::c_int, + pub last_error_message: *mut zend_string, + pub last_error_file: *mut zend_string, + pub last_error_lineno: ::std::os::raw::c_int, + pub php_sys_temp_dir: *mut ::std::os::raw::c_char, + pub disable_classes: *mut ::std::os::raw::c_char, + pub allow_url_include: bool, + pub max_input_nesting_level: zend_long, + pub max_input_vars: zend_long, + pub in_user_include: bool, + pub user_ini_filename: *mut ::std::os::raw::c_char, + pub user_ini_cache_ttl: zend_long, + pub request_order: *mut ::std::os::raw::c_char, + pub mail_x_header: bool, + pub mail_mixed_lf_and_crlf: bool, + pub mail_log: *mut ::std::os::raw::c_char, + pub in_error_log: bool, + pub syslog_facility: zend_long, + pub syslog_ident: *mut ::std::os::raw::c_char, + pub have_called_openlog: bool, + pub syslog_filter: zend_long, + pub error_log_mode: zend_long, +} +extern "C" { + pub static mut core_globals: _php_core_globals; +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _arg_separators { + pub output: *mut ::std::os::raw::c_char, + pub input: *mut ::std::os::raw::c_char, +} +pub type arg_separators = _arg_separators; #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct _zend_ini_entry { @@ -1417,6 +2152,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; } @@ -1482,3 +2236,82 @@ extern "C" { extern "C" { pub static mut zend_ce_stringable: *mut zend_class_entry; } +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct sapi_header_struct { + pub header: *mut ::std::os::raw::c_char, + pub header_len: usize, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct sapi_headers_struct { + pub headers: zend_llist, + pub http_response_code: ::std::os::raw::c_int, + pub send_default_content_type: ::std::os::raw::c_uchar, + pub mimetype: *mut ::std::os::raw::c_char, + pub http_status_line: *mut ::std::os::raw::c_char, +} +pub type sapi_post_entry = _sapi_post_entry; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct sapi_request_info { + pub request_method: *const ::std::os::raw::c_char, + pub query_string: *mut ::std::os::raw::c_char, + pub cookie_data: *mut ::std::os::raw::c_char, + pub content_length: zend_long, + pub path_translated: *mut ::std::os::raw::c_char, + pub request_uri: *mut ::std::os::raw::c_char, + pub request_body: *mut _php_stream, + pub content_type: *const ::std::os::raw::c_char, + pub headers_only: bool, + pub no_headers: bool, + pub headers_read: bool, + pub post_entry: *mut sapi_post_entry, + pub content_type_dup: *mut ::std::os::raw::c_char, + pub auth_user: *mut ::std::os::raw::c_char, + pub auth_password: *mut ::std::os::raw::c_char, + pub auth_digest: *mut ::std::os::raw::c_char, + pub argv0: *mut ::std::os::raw::c_char, + pub current_user: *mut ::std::os::raw::c_char, + pub current_user_length: ::std::os::raw::c_int, + pub argc: ::std::os::raw::c_int, + pub argv: *mut *mut ::std::os::raw::c_char, + pub proto_num: ::std::os::raw::c_int, +} +#[repr(C)] +pub struct _sapi_globals_struct { + pub server_context: *mut ::std::os::raw::c_void, + pub request_info: sapi_request_info, + pub sapi_headers: sapi_headers_struct, + pub read_post_bytes: i64, + pub post_read: ::std::os::raw::c_uchar, + pub headers_sent: ::std::os::raw::c_uchar, + pub global_stat: zend_stat_t, + pub default_mimetype: *mut ::std::os::raw::c_char, + pub default_charset: *mut ::std::os::raw::c_char, + pub rfc1867_uploaded_files: *mut HashTable, + pub post_max_size: zend_long, + pub options: ::std::os::raw::c_int, + pub sapi_started: bool, + pub global_request_time: f64, + pub known_post_content_types: HashTable, + pub callback_func: zval, + pub fci_cache: zend_fcall_info_cache, +} +pub type sapi_globals_struct = _sapi_globals_struct; +extern "C" { + pub static mut sapi_globals: sapi_globals_struct; +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _sapi_post_entry { + pub content_type: *mut ::std::os::raw::c_char, + pub content_type_len: u32, + pub post_reader: ::std::option::Option, + pub post_handler: ::std::option::Option< + unsafe extern "C" fn( + content_type_dup: *mut ::std::os::raw::c_char, + arg: *mut ::std::os::raw::c_void, + ), + >, +} diff --git a/src/builders/module.rs b/src/builders/module.rs index 6eaaf51c0..ee2b219fd 100644 --- a/src/builders/module.rs +++ b/src/builders/module.rs @@ -126,6 +126,20 @@ 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 841228ebf..441912f64 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/ffi.rs b/src/ffi.rs index 92614c475..465b50950 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -26,6 +26,9 @@ extern "C" { pub fn ext_php_rs_zend_object_alloc(obj_size: usize, ce: *mut zend_class_entry) -> *mut c_void; pub fn ext_php_rs_zend_object_release(obj: *mut zend_object); pub fn ext_php_rs_executor_globals() -> *mut zend_executor_globals; + pub fn ext_php_rs_process_globals() -> *mut php_core_globals; + pub fn ext_php_rs_sapi_globals() -> *mut sapi_globals_struct; + pub fn ext_php_rs_file_globals() -> *mut php_file_globals; } include!(concat!(env!("OUT_DIR"), "/bindings.rs")); diff --git a/src/flags.rs b/src/flags.rs index efe65292b..b722ffa0c 100644 --- a/src/flags.rs +++ b/src/flags.rs @@ -5,21 +5,24 @@ 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_INDIRECT, 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, - ZEND_ACC_RESOLVED_PARENT, ZEND_ACC_RETURN_REFERENCE, ZEND_ACC_STATIC, ZEND_ACC_STRICT_TYPES, - ZEND_ACC_TOP_LEVEL, ZEND_ACC_TRAIT, ZEND_ACC_TRAIT_CLONE, ZEND_ACC_UNRESOLVED_VARIANCE, - ZEND_ACC_USES_THIS, ZEND_ACC_USE_GUARDS, ZEND_ACC_VARIADIC, ZEND_HAS_STATIC_IN_METHODS, - Z_TYPE_FLAGS_SHIFT, _IS_BOOL, + 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_INDIRECT, 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, ZEND_ACC_RESOLVED_PARENT, + ZEND_ACC_RETURN_REFERENCE, ZEND_ACC_STATIC, ZEND_ACC_STRICT_TYPES, ZEND_ACC_TOP_LEVEL, + ZEND_ACC_TRAIT, ZEND_ACC_TRAIT_CLONE, ZEND_ACC_UNRESOLVED_VARIANCE, ZEND_ACC_USES_THIS, + ZEND_ACC_USE_GUARDS, ZEND_ACC_VARIADIC, ZEND_HAS_STATIC_IN_METHODS, Z_TYPE_FLAGS_SHIFT, + _IS_BOOL, }; use std::{convert::TryFrom, fmt::Display}; @@ -171,6 +174,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/wrapper.c b/src/wrapper.c index faf585e41..c88e2dab8 100644 --- a/src/wrapper.c +++ b/src/wrapper.c @@ -39,3 +39,37 @@ zend_executor_globals *ext_php_rs_executor_globals() { return &executor_globals; #endif } + +php_core_globals *ext_php_rs_process_globals() { +#ifdef ZTS +#ifdef ZEND_ENABLE_STATIC_TSRMLS_CACHE + return TSRMG_FAST_BULK_STATIC(core_globals_offset, php_core_globals); +#else + return TSRMG_FAST_BULK(core_globals_offset, php_core_globals *); +#endif +#else + return &core_globals; +#endif +} + + +sapi_globals_struct *ext_php_rs_sapi_globals() { +#ifdef ZTS +#ifdef ZEND_ENABLE_STATIC_TSRMLS_CACHE + return TSRMG_FAST_BULK_STATIC(sapi_globals_offset, sapi_globals_struct); +#else + return TSRMG_FAST_BULK(sapi_globals_offset, sapi_globals_struct *); +#endif +#else + return &sapi_globals; +#endif +} + + +php_file_globals *ext_php_rs_file_globals() { +#ifdef ZTS + return TSRMG_FAST_BULK(file_globals_id, php_file_globals *); +#else + return &file_globals; +#endif +} diff --git a/src/wrapper.h b/src/wrapper.h index 281326367..85d8d2176 100644 --- a/src/wrapper.h +++ b/src/wrapper.h @@ -17,9 +17,14 @@ #include "php.h" #include "ext/standard/info.h" +#include "ext/standard/php_var.h" +#include "ext/standard/file.h" #include "zend_exceptions.h" #include "zend_inheritance.h" #include "zend_interfaces.h" +#include "SAPI.h" +#include "php_variables.h" +#include "file.h" 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); @@ -29,4 +34,7 @@ void ext_php_rs_set_known_valid_utf8(zend_string *zs); const char *ext_php_rs_php_build_id(); void *ext_php_rs_zend_object_alloc(size_t obj_size, zend_class_entry *ce); void ext_php_rs_zend_object_release(zend_object *obj); -zend_executor_globals *ext_php_rs_executor_globals(); \ No newline at end of file +zend_executor_globals *ext_php_rs_executor_globals(); +php_core_globals *ext_php_rs_process_globals(); +sapi_globals_struct *ext_php_rs_sapi_globals(); +php_file_globals *ext_php_rs_file_globals(); diff --git a/src/zend/globals.rs b/src/zend/globals.rs index 7ba76c498..bf68e240d 100644 --- a/src/zend/globals.rs +++ b/src/zend/globals.rs @@ -1,13 +1,23 @@ -//! Types related to the PHP executor globals. - +//! Types related to the PHP executor, sapi and process globals. +use std::ffi::CStr; use std::ops::{Deref, DerefMut}; +use std::slice; +use std::str; use parking_lot::{const_rwlock, RwLock, RwLockReadGuard, RwLockWriteGuard}; use crate::boxed::ZBox; -use crate::ffi::{_zend_executor_globals, ext_php_rs_executor_globals}; +use crate::ffi::{ + _zend_executor_globals, ext_php_rs_executor_globals, ext_php_rs_file_globals, + ext_php_rs_process_globals, ext_php_rs_sapi_globals, php_core_globals, php_file_globals, + sapi_globals_struct, sapi_header_struct, sapi_headers_struct, sapi_request_info, + zend_is_auto_global, TRACK_VARS_COOKIE, TRACK_VARS_ENV, TRACK_VARS_FILES, TRACK_VARS_GET, + TRACK_VARS_POST, TRACK_VARS_REQUEST, TRACK_VARS_SERVER, +}; + +use crate::types::{ZendHashTable, ZendObject, ZendStr}; -use crate::types::{ZendHashTable, ZendObject}; +use super::linked_list::ZendLinkedListIterator; /// Stores global variables used in the PHP executor. pub type ExecutorGlobals = _zend_executor_globals; @@ -50,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`]. /// @@ -67,11 +82,336 @@ impl ExecutorGlobals { } } +/// Stores global variables used in the PHP executor. +pub type ProcessGlobals = php_core_globals; + +impl ProcessGlobals { + /// Returns a reference to the PHP process globals. + /// + /// The process globals are guarded by a RwLock. There can be multiple + /// immutable references at one time but only ever one mutable reference. + /// Attempting to retrieve the globals while already holding the global + /// guard will lead to a deadlock. Dropping the globals guard will release + /// the lock. + pub fn get() -> GlobalReadGuard { + // SAFETY: PHP executor globals are statically declared therefore should never + // return an invalid pointer. + let globals = unsafe { &*ext_php_rs_process_globals() }; + let guard = PROCESS_GLOBALS_LOCK.read(); + GlobalReadGuard { globals, guard } + } + + /// Returns a mutable reference to the PHP executor globals. + /// + /// The executor globals are guarded by a RwLock. There can be multiple + /// immutable references at one time but only ever one mutable reference. + /// Attempting to retrieve the globals while already holding the global + /// guard will lead to a deadlock. Dropping the globals guard will release + /// the lock. + pub fn get_mut() -> GlobalWriteGuard { + // SAFETY: PHP executor globals are statically declared therefore should never + // return an invalid pointer. + let globals = unsafe { &mut *ext_php_rs_process_globals() }; + let guard = PROCESS_GLOBALS_LOCK.write(); + GlobalWriteGuard { globals, guard } + } + + /// Get the HTTP Server variables. Equivalent of $_SERVER. + pub fn http_server_vars(&self) -> Option<&ZendHashTable> { + // $_SERVER is lazy-initted, we need to call zend_is_auto_global + // if it's not already populated. + if !self.http_globals[TRACK_VARS_SERVER as usize].is_array() { + let name = ZendStr::new("_SERVER", false).as_mut_ptr(); + unsafe { zend_is_auto_global(name) }; + } + if self.http_globals[TRACK_VARS_SERVER as usize].is_array() { + self.http_globals[TRACK_VARS_SERVER as usize].array() + } else { + None + } + } + + /// Get the HTTP POST variables. Equivalent of $_POST. + pub fn http_post_vars(&self) -> &ZendHashTable { + self.http_globals[TRACK_VARS_POST as usize] + .array() + .expect("Type is not a ZendArray") + } + + /// Get the HTTP GET variables. Equivalent of $_GET. + pub fn http_get_vars(&self) -> &ZendHashTable { + self.http_globals[TRACK_VARS_GET as usize] + .array() + .expect("Type is not a ZendArray") + } + + /// Get the HTTP Cookie variables. Equivalent of $_COOKIE. + pub fn http_cookie_vars(&self) -> &ZendHashTable { + self.http_globals[TRACK_VARS_COOKIE as usize] + .array() + .expect("Type is not a ZendArray") + } + + /// Get the HTTP Request variables. Equivalent of $_REQUEST. + pub fn http_request_vars(&self) -> &ZendHashTable { + self.http_globals[TRACK_VARS_REQUEST as usize] + .array() + .expect("Type is not a ZendArray") + } + + /// Get the HTTP Environment variables. Equivalent of $_ENV. + pub fn http_env_vars(&self) -> &ZendHashTable { + self.http_globals[TRACK_VARS_ENV as usize] + .array() + .expect("Type is not a ZendArray") + } + + /// Get the HTTP Files variables. Equivalent of $_FILES. + pub fn http_files_vars(&self) -> &ZendHashTable { + self.http_globals[TRACK_VARS_FILES as usize] + .array() + .expect("Type is not a ZendArray") + } +} + +/// Stores global variables used in the SAPI. +pub type SapiGlobals = sapi_globals_struct; + +impl SapiGlobals { + /// Returns a reference to the PHP process globals. + /// + /// The process globals are guarded by a RwLock. There can be multiple + /// immutable references at one time but only ever one mutable reference. + /// Attempting to retrieve the globals while already holding the global + /// guard will lead to a deadlock. Dropping the globals guard will release + /// the lock. + pub fn get() -> GlobalReadGuard { + // SAFETY: PHP executor globals are statically declared therefore should never + // return an invalid pointer. + let globals = unsafe { &*ext_php_rs_sapi_globals() }; + let guard = SAPI_GLOBALS_LOCK.read(); + GlobalReadGuard { globals, guard } + } + + /// Returns a mutable reference to the PHP executor globals. + /// + /// The executor globals are guarded by a RwLock. There can be multiple + /// immutable references at one time but only ever one mutable reference. + /// Attempting to retrieve the globals while already holding the global + /// guard will lead to a deadlock. Dropping the globals guard will release + /// the lock. + pub fn get_mut() -> GlobalWriteGuard { + // SAFETY: PHP executor globals are statically declared therefore should never + // return an invalid pointer. + let globals = unsafe { &mut *ext_php_rs_sapi_globals() }; + let guard = SAPI_GLOBALS_LOCK.write(); + GlobalWriteGuard { globals, guard } + } + // Get the request info for the Sapi. + pub fn request_info(&self) -> &SapiRequestInfo { + &self.request_info + } + + pub fn sapi_headers(&self) -> &SapiHeaders { + &self.sapi_headers + } +} + +pub type SapiHeaders = sapi_headers_struct; + +impl<'a> SapiHeaders { + pub fn headers(&'a mut self) -> ZendLinkedListIterator<'a, SapiHeader> { + self.headers.iter() + } +} + +pub type SapiHeader = sapi_header_struct; + +impl<'a> SapiHeader { + pub fn as_str(&'a self) -> &'a str { + unsafe { + let slice = slice::from_raw_parts(self.header as *const u8, self.header_len); + str::from_utf8(slice).expect("Invalid header string") + } + } + + pub fn name(&'a self) -> &'a str { + self.as_str().split(':').next().unwrap_or("").trim() + } + + pub fn value(&'a self) -> Option<&'a str> { + self.as_str().split(':').nth(1).map(|s| s.trim()) + } +} + +pub type SapiRequestInfo = sapi_request_info; + +impl SapiRequestInfo { + pub fn request_method(&self) -> Option<&str> { + if self.request_method.is_null() { + return None; + } + unsafe { CStr::from_ptr(self.request_method).to_str().ok() } + } + + pub fn query_string(&self) -> Option<&str> { + if self.query_string.is_null() { + return None; + } + unsafe { CStr::from_ptr(self.query_string).to_str().ok() } + } + + pub fn cookie_data(&self) -> Option<&str> { + if self.cookie_data.is_null() { + return None; + } + unsafe { CStr::from_ptr(self.cookie_data).to_str().ok() } + } + + pub fn content_length(&self) -> i64 { + self.content_length + } + + pub fn path_translated(&self) -> Option<&str> { + if self.path_translated.is_null() { + return None; + } + unsafe { CStr::from_ptr(self.path_translated).to_str().ok() } + } + + pub fn request_uri(&self) -> Option<&str> { + if self.request_uri.is_null() { + return None; + } + unsafe { CStr::from_ptr(self.request_uri).to_str().ok() } + } + + // Todo: request_body _php_stream + + pub fn content_type(&self) -> Option<&str> { + if self.content_type.is_null() { + return None; + } + unsafe { CStr::from_ptr(self.content_type).to_str().ok() } + } + + pub fn headers_only(&self) -> bool { + self.headers_only + } + + pub fn no_headers(&self) -> bool { + self.no_headers + } + + pub fn headers_read(&self) -> bool { + self.headers_read + } + + // Todo: post_entry sapi_post_entry + + pub fn auth_user(&self) -> Option<&str> { + if self.auth_user.is_null() { + return None; + } + unsafe { CStr::from_ptr(self.auth_user).to_str().ok() } + } + + pub fn auth_password(&self) -> Option<&str> { + if self.auth_password.is_null() { + return None; + } + unsafe { CStr::from_ptr(self.auth_password).to_str().ok() } + } + + pub fn auth_digest(&self) -> Option<&str> { + if self.auth_digest.is_null() { + return None; + } + unsafe { CStr::from_ptr(self.auth_digest).to_str().ok() } + } + + pub fn argv0(&self) -> Option<&str> { + if self.argv0.is_null() { + return None; + } + unsafe { CStr::from_ptr(self.argv0).to_str().ok() } + } + + pub fn current_user(&self) -> Option<&str> { + if self.current_user.is_null() { + return None; + } + unsafe { CStr::from_ptr(self.current_user).to_str().ok() } + } + + pub fn current_user_length(&self) -> i32 { + self.current_user_length + } + + pub fn argvc(&self) -> i32 { + self.argc + } + + pub fn argv(&self) -> Option<&str> { + if self.argv.is_null() { + return None; + } + unsafe { CStr::from_ptr(*self.argv).to_str().ok() } + } + + pub fn proto_num(&self) -> i32 { + self.proto_num + } +} + +/// Stores global variables used in the SAPI. +pub type FileGlobals = php_file_globals; + +impl FileGlobals { + /// Returns a reference to the PHP process globals. + /// + /// The process globals are guarded by a RwLock. There can be multiple + /// immutable references at one time but only ever one mutable reference. + /// Attempting to retrieve the globals while already holding the global + /// guard will lead to a deadlock. Dropping the globals guard will release + /// the lock. + pub fn get() -> GlobalReadGuard { + // SAFETY: PHP executor globals are statically declared therefore should never + // return an invalid pointer. + let globals = unsafe { ext_php_rs_file_globals().as_ref() } + .expect("Static file globals were invalid"); + let guard = FILE_GLOBALS_LOCK.read(); + GlobalReadGuard { globals, guard } + } + + /// Returns a mutable reference to the PHP executor globals. + /// + /// The executor globals are guarded by a RwLock. There can be multiple + /// immutable references at one time but only ever one mutable reference. + /// Attempting to retrieve the globals while already holding the global + /// guard will lead to a deadlock. Dropping the globals guard will release + /// the lock. + pub fn get_mut() -> GlobalWriteGuard { + // SAFETY: PHP executor globals are statically declared therefore should never + // return an invalid pointer. + let globals = unsafe { &mut *ext_php_rs_file_globals() }; + let guard = SAPI_GLOBALS_LOCK.write(); + GlobalWriteGuard { globals, guard } + } + + pub fn stream_wrappers(&self) -> Option<&'static ZendHashTable> { + unsafe { self.stream_wrappers.as_ref() } + } +} + /// Executor globals rwlock. /// /// PHP provides no indication if the executor globals are being accessed so /// this is only effective on the Rust side. static GLOBALS_LOCK: RwLock<()> = const_rwlock(()); +static PROCESS_GLOBALS_LOCK: RwLock<()> = const_rwlock(()); +static SAPI_GLOBALS_LOCK: RwLock<()> = const_rwlock(()); +static FILE_GLOBALS_LOCK: RwLock<()> = const_rwlock(()); /// Wrapper guard that contains a reference to a given type `T`. Dropping a /// guard releases the lock on the relevant rwlock. diff --git a/src/zend/linked_list.rs b/src/zend/linked_list.rs new file mode 100644 index 000000000..481b22979 --- /dev/null +++ b/src/zend/linked_list.rs @@ -0,0 +1,46 @@ +use std::marker::PhantomData; + +use crate::ffi::{zend_llist, zend_llist_element, zend_llist_get_next_ex}; + +pub type ZendLinkedList = zend_llist; + +impl ZendLinkedList { + pub fn iter(&self) -> ZendLinkedListIterator { + ZendLinkedListIterator::new(self) + } +} + +pub struct ZendLinkedListIterator<'a, T> { + list: &'a zend_llist, + position: *mut zend_llist_element, + _marker: PhantomData, +} + +impl<'a, T> ZendLinkedListIterator<'a, T> { + fn new(list: &'a ZendLinkedList) -> Self { + ZendLinkedListIterator { + list, + position: list.head, + _marker: PhantomData, + } + } +} + +impl<'a, T: 'a> Iterator for ZendLinkedListIterator<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option { + if self.position.is_null() { + return None; + } + let ptr = unsafe { (*self.position).data.as_mut_ptr() }; + let value = unsafe { &*(ptr as *const T as *mut T) }; + unsafe { + zend_llist_get_next_ex( + self.list as *const ZendLinkedList as *mut ZendLinkedList, + &mut self.position, + ) + }; + Some(value) + } +} diff --git a/src/zend/mod.rs b/src/zend/mod.rs index 74547f044..9426aae57 100644 --- a/src/zend/mod.rs +++ b/src/zend/mod.rs @@ -7,6 +7,7 @@ mod ex; mod function; mod globals; mod handlers; +mod linked_list; mod module; use crate::{error::Result, ffi::php_printf}; @@ -17,7 +18,11 @@ pub use class::ClassEntry; pub use ex::ExecuteData; pub use function::FunctionEntry; pub use globals::ExecutorGlobals; +pub use globals::FileGlobals; +pub use globals::ProcessGlobals; +pub use globals::SapiGlobals; pub use handlers::ZendObjectHandlers; +pub use linked_list::ZendLinkedList; pub use module::ModuleEntry; // Used as the format string for `php_printf`.