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