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