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