mirror of
https://github.com/danog/ext-php-rs.git
synced 2024-12-02 09:37:51 +01:00
Merge pull request #249 from davidcole1340/process-globals
Add streams API, ProcessGlobals, FileGlobals and SapiGlobals
This commit is contained in:
commit
5de7c7f167
@ -245,7 +245,6 @@ bind! {
|
||||
zend_class_serialize_deny,
|
||||
zend_class_unserialize_deny,
|
||||
zend_executor_globals,
|
||||
sapi_globals_struct,
|
||||
sapi_module_struct,
|
||||
zend_objects_store_del,
|
||||
zend_hash_move_forward_ex,
|
||||
@ -257,13 +256,39 @@ bind! {
|
||||
gc_possible_root,
|
||||
ZEND_ACC_NOT_SERIALIZABLE,
|
||||
executor_globals,
|
||||
php_core_globals,
|
||||
core_globals,
|
||||
sapi_globals_struct,
|
||||
sapi_globals,
|
||||
sapi_module,
|
||||
php_printf,
|
||||
__zend_malloc,
|
||||
tsrm_get_ls_cache,
|
||||
executor_globals_offset,
|
||||
core_globals_offset,
|
||||
sapi_globals_offset,
|
||||
php_file_globals,
|
||||
file_globals,
|
||||
file_globals_id,
|
||||
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,
|
||||
php_register_url_stream_wrapper,
|
||||
php_stream_locate_url_wrapper,
|
||||
php_unregister_url_stream_wrapper,
|
||||
php_unregister_url_stream_wrapper_volatile,
|
||||
php_register_url_stream_wrapper_volatile,
|
||||
php_stream_wrapper,
|
||||
php_stream_stdio_ops,
|
||||
zend_atomic_bool_store,
|
||||
zend_interrupt_function,
|
||||
zend_eval_string,
|
||||
|
@ -182,6 +182,13 @@ pub const ZEND_MODULE_API_NO: u32 = 20230831;
|
||||
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 PHP_INI_USER: u32 = 1;
|
||||
pub const PHP_INI_PERDIR: u32 = 2;
|
||||
pub const PHP_INI_SYSTEM: u32 = 4;
|
||||
@ -506,6 +513,19 @@ pub struct _zend_llist {
|
||||
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,
|
||||
@ -1469,6 +1489,9 @@ pub struct _zend_executor_globals {
|
||||
pub reserved_stack_size: zend_ulong,
|
||||
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)]
|
||||
@ -2094,6 +2117,127 @@ impl _php_stream {
|
||||
__bindgen_bitfield_unit
|
||||
}
|
||||
}
|
||||
extern "C" {
|
||||
pub static mut php_stream_stdio_ops: php_stream_ops;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn php_register_url_stream_wrapper(
|
||||
protocol: *const ::std::os::raw::c_char,
|
||||
wrapper: *const php_stream_wrapper,
|
||||
) -> zend_result;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn php_unregister_url_stream_wrapper(
|
||||
protocol: *const ::std::os::raw::c_char,
|
||||
) -> zend_result;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn php_register_url_stream_wrapper_volatile(
|
||||
protocol: *mut zend_string,
|
||||
wrapper: *mut php_stream_wrapper,
|
||||
) -> zend_result;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn php_unregister_url_stream_wrapper_volatile(protocol: *mut zend_string) -> zend_result;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn php_stream_locate_url_wrapper(
|
||||
path: *const ::std::os::raw::c_char,
|
||||
path_for_open: *mut *const ::std::os::raw::c_char,
|
||||
options: ::std::os::raw::c_int,
|
||||
) -> *mut php_stream_wrapper;
|
||||
}
|
||||
pub type php_core_globals = _php_core_globals;
|
||||
#[repr(C)]
|
||||
pub struct _php_core_globals {
|
||||
pub output_buffering: zend_long,
|
||||
pub implicit_flush: bool,
|
||||
pub enable_dl: bool,
|
||||
pub display_errors: u8,
|
||||
pub display_startup_errors: bool,
|
||||
pub log_errors: bool,
|
||||
pub ignore_repeated_errors: bool,
|
||||
pub ignore_repeated_source: bool,
|
||||
pub report_memleaks: 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 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 open_basedir_modified: bool,
|
||||
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 html_errors: bool,
|
||||
pub xmlrpc_errors: bool,
|
||||
pub docref_root: *mut ::std::os::raw::c_char,
|
||||
pub docref_ext: *mut ::std::os::raw::c_char,
|
||||
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_lineno: ::std::os::raw::c_int,
|
||||
pub last_error_message: *mut zend_string,
|
||||
pub last_error_file: *mut zend_string,
|
||||
pub php_sys_temp_dir: *mut ::std::os::raw::c_char,
|
||||
pub disable_classes: *mut ::std::os::raw::c_char,
|
||||
pub max_input_nesting_level: zend_long,
|
||||
pub max_input_vars: zend_long,
|
||||
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_log: *mut ::std::os::raw::c_char,
|
||||
pub mail_x_header: bool,
|
||||
pub mail_mixed_lf_and_crlf: bool,
|
||||
pub in_error_log: bool,
|
||||
pub allow_url_include: bool,
|
||||
pub in_user_include: bool,
|
||||
pub have_called_openlog: bool,
|
||||
pub syslog_facility: zend_long,
|
||||
pub syslog_ident: *mut ::std::os::raw::c_char,
|
||||
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_def {
|
||||
@ -2201,6 +2345,37 @@ extern "C" {
|
||||
extern "C" {
|
||||
pub fn php_info_print_table_end();
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct hostent {
|
||||
pub h_name: *mut ::std::os::raw::c_char,
|
||||
pub h_aliases: *mut *mut ::std::os::raw::c_char,
|
||||
pub h_addrtype: ::std::os::raw::c_int,
|
||||
pub h_length: ::std::os::raw::c_int,
|
||||
pub h_addr_list: *mut *mut ::std::os::raw::c_char,
|
||||
}
|
||||
#[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,
|
||||
pub tmp_host_info: hostent,
|
||||
pub tmp_host_buf: *mut ::std::os::raw::c_char,
|
||||
pub tmp_host_buf_len: usize,
|
||||
}
|
||||
extern "C" {
|
||||
pub static mut file_globals: php_file_globals;
|
||||
}
|
||||
extern "C" {
|
||||
pub static mut zend_ce_throwable: *mut zend_class_entry;
|
||||
}
|
||||
|
13
src/error.rs
13
src/error.rs
@ -65,6 +65,10 @@ pub enum Error {
|
||||
IntegerOverflow,
|
||||
/// An exception was thrown in a function.
|
||||
Exception(ZBox<ZendObject>),
|
||||
/// A failure occurred while registering the stream wrapper
|
||||
StreamWrapperRegistrationFailure,
|
||||
/// A failure occurred while unregistering the stream wrapper
|
||||
StreamWrapperUnregistrationFailure,
|
||||
}
|
||||
|
||||
impl Display for Error {
|
||||
@ -99,6 +103,15 @@ impl Display for Error {
|
||||
write!(f, "Converting integer arguments resulted in an overflow.")
|
||||
}
|
||||
Error::Exception(e) => write!(f, "Exception was thrown: {e:?}"),
|
||||
Error::StreamWrapperRegistrationFailure => {
|
||||
write!(f, "A failure occurred while registering the stream wrapper")
|
||||
}
|
||||
Error::StreamWrapperUnregistrationFailure => {
|
||||
write!(
|
||||
f,
|
||||
"A failure occurred while unregistering the stream wrapper"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -69,8 +69,8 @@ impl PhpException {
|
||||
|
||||
/// Set the Zval object for the exception.
|
||||
///
|
||||
/// Exceptions can be based of instantiated Zval objects when you are throwing a custom exception with
|
||||
/// stateful properties.
|
||||
/// Exceptions can be based of instantiated Zval objects when you are
|
||||
/// throwing a custom exception with stateful properties.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
|
@ -26,7 +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;
|
||||
pub fn ext_php_rs_sapi_module() -> *mut sapi_module_struct;
|
||||
pub fn ext_php_rs_zend_try_catch(
|
||||
func: unsafe extern "C" fn(*const c_void) -> *const c_void,
|
||||
|
@ -222,7 +222,8 @@ impl Zval {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the zval if it is an internal indirect reference.
|
||||
/// Returns a mutable reference to the zval if it is an internal indirect
|
||||
/// reference.
|
||||
pub fn indirect_mut(&self) -> Option<&mut Zval> {
|
||||
if self.is_indirect() {
|
||||
Some(unsafe { &mut *(self.value.zv as *mut Zval) })
|
||||
|
@ -40,6 +40,18 @@ zend_executor_globals *ext_php_rs_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
|
||||
@ -52,6 +64,14 @@ sapi_globals_struct *ext_php_rs_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
|
||||
}
|
||||
|
||||
sapi_module_struct *ext_php_rs_sapi_module() {
|
||||
return &sapi_module;
|
||||
}
|
||||
|
@ -17,9 +17,12 @@
|
||||
#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 "php_variables.h"
|
||||
#include "zend_ini.h"
|
||||
#include "main/SAPI.h"
|
||||
|
||||
@ -31,8 +34,10 @@ 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();;
|
||||
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();
|
||||
sapi_module_struct *ext_php_rs_sapi_module();
|
||||
bool ext_php_rs_zend_try_catch(void* (*callback)(void *), void *ctx, void **result);
|
||||
void ext_php_rs_zend_bailout();
|
||||
|
@ -1,7 +1,10 @@
|
||||
//! Types related to the PHP executor globals.
|
||||
//! Types related to the PHP executor, sapi and process globals.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::CStr;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::slice;
|
||||
use std::str;
|
||||
|
||||
use parking_lot::{const_rwlock, RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
|
||||
@ -9,17 +12,21 @@ use crate::boxed::ZBox;
|
||||
#[cfg(php82)]
|
||||
use crate::ffi::zend_atomic_bool_store;
|
||||
use crate::ffi::{
|
||||
_sapi_globals_struct, _sapi_module_struct, _zend_executor_globals, ext_php_rs_executor_globals,
|
||||
ext_php_rs_sapi_globals, ext_php_rs_sapi_module, zend_ini_entry,
|
||||
_sapi_module_struct, _zend_executor_globals, ext_php_rs_executor_globals,
|
||||
ext_php_rs_file_globals, ext_php_rs_process_globals, ext_php_rs_sapi_globals,
|
||||
ext_php_rs_sapi_module, php_core_globals, php_file_globals, sapi_globals_struct,
|
||||
sapi_header_struct, sapi_headers_struct, sapi_request_info, zend_ini_entry,
|
||||
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};
|
||||
|
||||
use crate::types::{ZendHashTable, ZendObject, ZendStr};
|
||||
|
||||
use super::linked_list::ZendLinkedListIterator;
|
||||
|
||||
/// Stores global variables used in the PHP executor.
|
||||
pub type ExecutorGlobals = _zend_executor_globals;
|
||||
|
||||
/// Stores global SAPI variables used in the PHP executor.
|
||||
pub type SapiGlobals = _sapi_globals_struct;
|
||||
|
||||
/// Stores the SAPI module used in the PHP executor.
|
||||
pub type SapiModule = _sapi_module_struct;
|
||||
|
||||
@ -146,40 +153,6 @@ impl ExecutorGlobals {
|
||||
}
|
||||
}
|
||||
|
||||
impl SapiGlobals {
|
||||
/// Returns a reference to the PHP SAPI 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() -> GlobalReadGuard<Self> {
|
||||
// SAFETY: PHP executor globals are statically declared therefore should never
|
||||
// return an invalid pointer.
|
||||
let globals = unsafe { ext_php_rs_sapi_globals().as_ref() }
|
||||
.expect("Static executor globals were invalid");
|
||||
let guard = SAPI_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<Self> {
|
||||
// SAFETY: PHP executor globals are statically declared therefore should never
|
||||
// return an invalid pointer.
|
||||
let globals = unsafe { ext_php_rs_sapi_globals().as_mut() }
|
||||
.expect("Static executor globals were invalid");
|
||||
let guard = SAPI_LOCK.write();
|
||||
GlobalWriteGuard { globals, guard }
|
||||
}
|
||||
}
|
||||
|
||||
impl SapiModule {
|
||||
/// Returns a reference to the PHP SAPI module.
|
||||
///
|
||||
@ -214,17 +187,336 @@ impl SapiModule {
|
||||
}
|
||||
}
|
||||
|
||||
/// 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<Self> {
|
||||
// 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<Self> {
|
||||
// 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<Self> {
|
||||
// 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<Self> {
|
||||
// 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<Self> {
|
||||
// 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<Self> {
|
||||
// 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(());
|
||||
|
||||
/// SAPI globals rwlock.
|
||||
///
|
||||
/// PHP provides no indication if the executor globals are being accessed so
|
||||
/// this is only effective on the Rust side.
|
||||
static SAPI_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(());
|
||||
|
||||
/// SAPI globals rwlock.
|
||||
///
|
||||
|
46
src/zend/linked_list.rs
Normal file
46
src/zend/linked_list.rs
Normal file
@ -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<T>(&self) -> ZendLinkedListIterator<T> {
|
||||
ZendLinkedListIterator::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ZendLinkedListIterator<'a, T> {
|
||||
list: &'a zend_llist,
|
||||
position: *mut zend_llist_element,
|
||||
_marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
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<Self::Item> {
|
||||
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)
|
||||
}
|
||||
}
|
@ -8,7 +8,9 @@ mod function;
|
||||
mod globals;
|
||||
mod handlers;
|
||||
mod ini_entry_def;
|
||||
mod linked_list;
|
||||
mod module;
|
||||
mod streams;
|
||||
mod try_catch;
|
||||
|
||||
use crate::{
|
||||
@ -23,11 +25,15 @@ pub use ex::ExecuteData;
|
||||
pub use function::Function;
|
||||
pub use function::FunctionEntry;
|
||||
pub use globals::ExecutorGlobals;
|
||||
pub use globals::FileGlobals;
|
||||
pub use globals::ProcessGlobals;
|
||||
pub use globals::SapiGlobals;
|
||||
pub use globals::SapiModule;
|
||||
pub use handlers::ZendObjectHandlers;
|
||||
pub use ini_entry_def::IniEntryDef;
|
||||
pub use linked_list::ZendLinkedList;
|
||||
pub use module::ModuleEntry;
|
||||
pub use streams::*;
|
||||
#[cfg(feature = "embed")]
|
||||
pub(crate) use try_catch::panic_wrapper;
|
||||
pub use try_catch::{bailout, try_catch};
|
||||
|
101
src/zend/streams.rs
Normal file
101
src/zend/streams.rs
Normal file
@ -0,0 +1,101 @@
|
||||
use std::ptr::{self, NonNull};
|
||||
|
||||
use crate::{
|
||||
error::Error,
|
||||
ffi::{
|
||||
php_register_url_stream_wrapper, php_register_url_stream_wrapper_volatile, php_stream,
|
||||
php_stream_context, php_stream_locate_url_wrapper, php_stream_wrapper,
|
||||
php_stream_wrapper_ops, php_unregister_url_stream_wrapper,
|
||||
php_unregister_url_stream_wrapper_volatile, zend_string,
|
||||
},
|
||||
types::ZendStr,
|
||||
};
|
||||
|
||||
pub type StreamWrapper = php_stream_wrapper;
|
||||
|
||||
pub type StreamOpener = unsafe extern "C" fn(
|
||||
*mut StreamWrapper,
|
||||
*const std::ffi::c_char,
|
||||
*const std::ffi::c_char,
|
||||
i32,
|
||||
*mut *mut zend_string,
|
||||
*mut php_stream_context,
|
||||
i32,
|
||||
*const std::ffi::c_char,
|
||||
u32,
|
||||
*const std::ffi::c_char,
|
||||
u32,
|
||||
) -> *mut Stream;
|
||||
|
||||
impl StreamWrapper {
|
||||
pub fn get(name: &str) -> Option<&Self> {
|
||||
unsafe {
|
||||
let result = php_stream_locate_url_wrapper(name.as_ptr().cast(), ptr::null_mut(), 0);
|
||||
Some(NonNull::new(result)?.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_mut(name: &str) -> Option<&mut Self> {
|
||||
unsafe {
|
||||
let result = php_stream_locate_url_wrapper(name.as_ptr().cast(), ptr::null_mut(), 0);
|
||||
Some(NonNull::new(result)?.as_mut())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register(self, name: &str) -> Result<Self, Error> {
|
||||
// We have to convert it to a static so owned streamwrapper doesn't get dropped.
|
||||
let copy = Box::new(self);
|
||||
let copy = Box::leak(copy);
|
||||
let name = std::ffi::CString::new(name).expect("Could not create C string for name!");
|
||||
let result = unsafe { php_register_url_stream_wrapper(name.as_ptr(), copy) };
|
||||
if result == 0 {
|
||||
Ok(*copy)
|
||||
} else {
|
||||
Err(Error::StreamWrapperRegistrationFailure)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_volatile(self, name: &str) -> Result<Self, Error> {
|
||||
// We have to convert it to a static so owned streamwrapper doesn't get dropped.
|
||||
let copy = Box::new(self);
|
||||
let copy = Box::leak(copy);
|
||||
let name = ZendStr::new(name, false);
|
||||
let result =
|
||||
unsafe { php_register_url_stream_wrapper_volatile((*name).as_ptr() as _, copy) };
|
||||
if result == 0 {
|
||||
Ok(*copy)
|
||||
} else {
|
||||
Err(Error::StreamWrapperRegistrationFailure)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unregister(name: &str) -> Result<(), Error> {
|
||||
let name = std::ffi::CString::new(name).expect("Could not create C string for name!");
|
||||
match unsafe { php_unregister_url_stream_wrapper(name.as_ptr()) } {
|
||||
0 => Ok(()),
|
||||
_ => Err(Error::StreamWrapperUnregistrationFailure),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unregister_volatile(name: &str) -> Result<(), Error> {
|
||||
let name = ZendStr::new(name, false);
|
||||
match unsafe { php_unregister_url_stream_wrapper_volatile((*name).as_ptr() as _) } {
|
||||
0 => Ok(()),
|
||||
_ => Err(Error::StreamWrapperUnregistrationFailure),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wops(&self) -> &php_stream_wrapper_ops {
|
||||
unsafe { &*self.wops }
|
||||
}
|
||||
|
||||
pub fn wops_mut(&mut self) -> &mut php_stream_wrapper_ops {
|
||||
unsafe { &mut *(self.wops as *mut php_stream_wrapper_ops) }
|
||||
}
|
||||
}
|
||||
|
||||
pub type Stream = php_stream;
|
||||
|
||||
pub type StreamWrapperOps = php_stream_wrapper_ops;
|
||||
|
||||
impl StreamWrapperOps {}
|
Loading…
Reference in New Issue
Block a user