diff --git a/src/embed/mod.rs b/src/embed/mod.rs index d7e03d5d5..2c9168bd5 100644 --- a/src/embed/mod.rs +++ b/src/embed/mod.rs @@ -1,3 +1,9 @@ +//! Provides implementations for running php code from rust. +//! It only works on linux for now and you should have `php-embed` installed +//! +//! This crate was only test with PHP 8.2 please report any issue with other version +//! You should only use this crate for test purpose, it's not production ready + mod ffi; use crate::boxed::ZBox; @@ -9,7 +15,7 @@ use crate::ffi::{ use crate::types::{ZendObject, Zval}; use crate::zend::ExecutorGlobals; use parking_lot::{const_rwlock, RwLock}; -use std::ffi::{c_char, c_void, CString}; +use std::ffi::{c_char, c_void, CString, NulError}; use std::path::Path; use std::ptr::null_mut; @@ -19,13 +25,44 @@ pub struct Embed; pub enum EmbedError { InitError, ExecuteError(Option>), + ExecuteScriptError, + InvalidEvalString(NulError), + InvalidPath, } static RUN_FN_LOCK: RwLock<()> = const_rwlock(()); impl Embed { - pub fn run_script>(path: P) -> bool { - let path = CString::new(path.as_ref().to_str().unwrap()).unwrap(); + /// Run a php script from a file + /// + /// This function will only work correctly when used inside the `Embed::run` function + /// otherwise behavior is unexpected + /// + /// # Returns + /// + /// * `Ok(())` - The script was executed successfully + /// * `Err(EmbedError)` - An error occured during the execution of the script + /// + /// # Example + /// + /// ``` + /// use ext_php_rs::embed::Embed; + /// + /// Embed::run(|| { + /// let result = Embed::run_script("src/embed/test-script.php"); + /// + /// assert!(result.is_ok()); + /// }); + /// ``` + pub fn run_script>(path: P) -> Result<(), EmbedError> { + let path = match path.as_ref().to_str() { + Some(path) => match CString::new(path) { + Ok(path) => path, + Err(err) => return Err(EmbedError::InvalidEvalString(err)), + }, + None => return Err(EmbedError::InvalidPath), + }; + let mut file_handle = zend_file_handle { handle: _zend_file_handle__bindgen_ty_1 { fp: null_mut() }, filename: null_mut(), @@ -41,9 +78,32 @@ impl Embed { zend_stream_init_filename(&mut file_handle, path.as_ptr()); } - unsafe { php_execute_script(&mut file_handle) } + if unsafe { php_execute_script(&mut file_handle) } { + Ok(()) + } else { + Err(EmbedError::ExecuteScriptError) + } } + /// Start and run embed sapi engine + /// + /// This function will allow to run php code from rust, the same PHP context is keep between calls + /// inside the function passed to this method. + /// Which means subsequent calls to `Embed::eval` or `Embed::run_script` will be able to access + /// variables defined in previous calls + /// + /// # Example + /// + /// ``` + /// use ext_php_rs::embed::Embed; + /// + /// Embed::run(|| { + /// let _ = Embed::eval("$foo = 'foo';"); + /// let foo = Embed::eval("$foo;"); + /// assert!(foo.is_ok()); + /// assert_eq!(foo.unwrap().string().unwrap(), "foo"); + /// }); + /// ``` pub fn run(func: F) { // @TODO handle php thread safe // @@ -65,8 +125,35 @@ impl Embed { } } + /// Evaluate a php code + /// + /// This function will only work correctly when used inside the `Embed::run` function + /// + /// # Returns + /// + /// * `Ok(Zval)` - The result of the evaluation + /// * `Err(EmbedError)` - An error occured during the evaluation + /// + /// # Example + /// + /// ``` + /// use ext_php_rs::embed::Embed; + /// + /// Embed::run(|| { + /// let foo = Embed::eval("$foo = 'foo';"); + /// assert!(foo.is_ok()); + /// }); + /// ``` + /// + /// # Panics + /// + /// This function will panic if the code cannot be converted to a CString (because it contains null bytes) pub fn eval(code: &str) -> Result { - let cstr = CString::new(code).unwrap(); + let cstr = match CString::new(code) { + Ok(cstr) => cstr, + Err(err) => return Err(EmbedError::InvalidEvalString(err)), + }; + let mut result = Zval::new(); // this eval is very limited as it only allow simple code, it's the same eval used by php -r @@ -115,7 +202,7 @@ mod tests { Embed::run(|| { let result = Embed::run_script("src/embed/test-script.php"); - assert!(result); + assert!(result.is_ok()); let zval = Embed::eval("$foo;").unwrap(); @@ -132,7 +219,7 @@ mod tests { Embed::run(|| { let result = Embed::run_script("src/embed/test-script-exception.php"); - assert!(!result); + assert!(!result.is_ok()); }); } }