Skip to main content

ext_php_rs/zend/
mod.rs

1//! Types used to interact with the Zend engine.
2
3mod _type;
4mod bailout_guard;
5pub mod ce;
6mod class;
7#[cfg(feature = "observer")]
8pub(crate) mod error_observer;
9mod ex;
10#[cfg(feature = "observer")]
11pub(crate) mod exception_observer;
12mod function;
13mod globals;
14mod handlers;
15mod ini_entry_def;
16mod linked_list;
17mod module;
18pub(crate) mod module_globals;
19#[cfg(feature = "observer")]
20pub(crate) mod observer;
21mod streams;
22mod try_catch;
23
24use crate::{
25    error::Result,
26    ffi::{php_output_write, php_printf, sapi_module},
27};
28use std::ffi::CString;
29use std::os::raw::c_char;
30
31pub use _type::ZendType;
32pub use bailout_guard::BailoutGuard;
33pub use bailout_guard::run_bailout_cleanups;
34pub use class::ClassEntry;
35#[cfg(feature = "observer")]
36pub use error_observer::{BacktraceFrame, ErrorInfo, ErrorObserver, ErrorType};
37pub use ex::ExecuteData;
38#[cfg(feature = "observer")]
39pub use exception_observer::{ExceptionInfo, ExceptionObserver};
40pub use function::Function;
41pub use function::FunctionEntry;
42pub use globals::ExecutorGlobals;
43pub use globals::FileGlobals;
44pub use globals::ProcessGlobals;
45pub use globals::SapiGlobals;
46pub use globals::SapiHeader;
47pub use globals::SapiHeaders;
48pub use globals::SapiModule;
49pub use handlers::ZendObjectHandlers;
50pub use ini_entry_def::IniEntryDef;
51pub use linked_list::ZendLinkedList;
52pub use module::{ModuleEntry, StaticModuleEntry, cleanup_module_allocations};
53pub use module_globals::{ModuleGlobal, ModuleGlobals};
54#[cfg(feature = "observer")]
55pub use observer::{FcallInfo, FcallObserver};
56pub use streams::*;
57#[cfg(feature = "embed")]
58pub(crate) use try_catch::panic_wrapper;
59pub use try_catch::{CatchError, bailout, try_catch, try_catch_first};
60
61// Used as the format string for `php_printf`.
62const FORMAT_STR: &[u8] = b"%s\0";
63
64/// Prints to stdout using the `php_printf` function.
65///
66/// Also see the [`php_print`] and [`php_println`] macros.
67///
68/// # Arguments
69///
70/// * message - The message to print to stdout.
71///
72/// # Errors
73///
74/// * If the message could not be converted to a [`CString`].
75pub fn printf(message: &str) -> Result<()> {
76    let message = CString::new(message)?;
77    unsafe {
78        php_printf(FORMAT_STR.as_ptr().cast(), message.as_ptr());
79    };
80    Ok(())
81}
82
83/// Writes binary data to PHP's output stream (stdout).
84///
85/// Unlike [`printf`], this function is binary-safe and can handle data
86/// containing NUL bytes. It uses the SAPI module's `ub_write` function
87/// which accepts a pointer and length, allowing arbitrary binary data.
88///
89/// Also see the [`php_write!`] macro.
90///
91/// # Arguments
92///
93/// * `data` - The binary data to write to stdout.
94///
95/// # Returns
96///
97/// The number of bytes written.
98///
99/// # Errors
100///
101/// Returns [`crate::error::Error::SapiWriteUnavailable`] if the SAPI's
102/// `ub_write` function is not available.
103///
104/// # Example
105///
106/// ```ignore
107/// use ext_php_rs::zend::write;
108///
109/// // Write binary data including NUL bytes
110/// let data = b"Hello\x00World";
111/// write(data).expect("Failed to write data");
112/// ```
113pub fn write(data: &[u8]) -> Result<usize> {
114    unsafe {
115        if let Some(ub_write) = sapi_module.ub_write {
116            Ok(ub_write(data.as_ptr().cast::<c_char>(), data.len()))
117        } else {
118            Err(crate::error::Error::SapiWriteUnavailable)
119        }
120    }
121}
122
123/// Writes binary data to PHP's output stream with output buffering support.
124///
125/// This function is binary-safe (can handle NUL bytes) AND respects PHP's
126/// output buffering (`ob_start()`). Use this when you need both binary-safe
127/// output and output buffering compatibility.
128///
129/// # Arguments
130///
131/// * `data` - The binary data to write.
132///
133/// # Returns
134///
135/// The number of bytes written.
136///
137/// # Comparison
138///
139/// | Function | Binary-safe | Output Buffering |
140/// |----------|-------------|------------------|
141/// | [`printf`] | No | Yes |
142/// | [`write()`] | Yes | No (unbuffered) |
143/// | [`output_write`] | Yes | Yes |
144///
145/// # Example
146///
147/// ```ignore
148/// use ext_php_rs::zend::output_write;
149///
150/// // Binary data that will be captured by ob_start()
151/// let data = b"Hello\x00World";
152/// output_write(data);
153/// ```
154#[inline]
155#[must_use]
156pub fn output_write(data: &[u8]) -> usize {
157    unsafe { php_output_write(data.as_ptr().cast::<c_char>(), data.len()) }
158}
159
160/// Get the name of the SAPI module.
161///
162/// # Panics
163///
164/// * If the module name is not a valid [`CStr`]
165///
166/// [`CStr`]: std::ffi::CStr
167pub fn php_sapi_name() -> String {
168    let c_str = unsafe { std::ffi::CStr::from_ptr(sapi_module.name) };
169    c_str.to_str().expect("Unable to parse CStr").to_string()
170}