src/main.rs
use ext_php_rs::builders::SapiBuilder;
use ext_php_rs::embed::{ext_php_rs_sapi_shutdown, ext_php_rs_sapi_startup, Embed};
use ext_php_rs::ffi::{
php_module_shutdown, php_module_startup, php_request_shutdown, php_request_startup, sapi_shutdown,
sapi_startup, ZEND_RESULT_CODE_SUCCESS,
};
use ext_php_rs::zend::try_catch_first;
use std::ffi::c_char;
use std::sync::Mutex;
// PHP は複数SAPI同時起動が苦手なので直列化(tests/sapi.rs でも同様):contentReference[oaicite:3]{index=3}
static SAPI_MUTEX: Mutex<()> = Mutex::new(());
static OUTPUT: Mutex<String> = Mutex::new(String::new());
// ub_write: PHP の unbuffered output をここで受け取る:contentReference[oaicite:4]{index=4}
extern "C" fn ub_write_capture(buf: *const c_char, len: usize) -> usize {
if buf.is_null() || len == 0 {
return 0;
}
let bytes = unsafe { std::slice::from_raw_parts(buf as *const u8, len) };
let s = String::from_utf8_lossy(bytes);
// 追記して回収
let mut out = OUTPUT.lock().unwrap();
out.push_str(&s);
len
}
fn main() {
let _guard = SAPI_MUTEX.lock().unwrap();
// 1) SAPI Module を構築(ub_write を差し替え)
let sapi = SapiBuilder::new("capture", "Capture SAPI")
.ub_write_function(ub_write_capture)
.build()
.expect("build sapi")
.into_raw();
// 2) ライフサイクル開始(C shim + sapi_startup + module_startup)
unsafe { ext_php_rs_sapi_startup() };
unsafe { sapi_startup(sapi) };
unsafe { php_module_startup(sapi, std::ptr::null_mut()) };
// 3) “1リクエスト” を開始(これをやらないと多くのAPIが動きません)
let rc = unsafe { php_request_startup() };
assert_eq!(rc, ZEND_RESULT_CODE_SUCCESS);
// 4) PHP を実行(例:ファイル実行)
let _ = try_catch_first(|| {
// 出力を回収したいので run_script を使う(echo が ub_write に流れる)
Embed::run_script("script.php").expect("run_script failed");
// 返り値が欲しいなら include を eval で:
// let z = Embed::eval("include 'script.php';").unwrap();
// eprintln!("return zval = {:?}", z);
});
// 5) リクエスト終了 → module/sapi 終了
unsafe { php_request_shutdown(std::ptr::null_mut()) };
unsafe { php_module_shutdown() };
unsafe { sapi_shutdown() };
unsafe { ext_php_rs_sapi_shutdown() };
// 6) 回収結果を表示
let out = OUTPUT.lock().unwrap().clone();
println!("=== captured output ===\n{out}");
}