| Crates.io | ripht-php-sapi |
| lib.rs | ripht-php-sapi |
| version | 0.1.0-rc.7 |
| created_at | 2025-12-23 06:41:14.255966+00 |
| updated_at | 2026-01-07 04:35:04.931523+00 |
| description | Ripht PHP SAPI - A PHP SAPI written in Rust to expose safe and convenient APIs to encourage additional Rust tooling development for PHP |
| homepage | https://github.com/jhavenz/ripht-php-sapi |
| repository | https://github.com/jhavenz/ripht-php-sapi |
| max_upload_size | |
| id | 2000909 |
| size | 337,413 |
Safe, pragmatic Rust bindings for embedding PHP via the embed SAPI.
Provide tooling that will allow additional PHP tooling to be built in Rust.
I hadn't seen another Rust crate offering comparable features.
I'm planning to build more tooling on this (stay tuned...).
This crate requires PHP built with the embed SAPI as a static library:
./configure --enable-embed=static --disable-zts [other options...]
make && make install
Set RIPHT_PHP_SAPI_PREFIX to your PHP installation root containing:
lib/libphp.a (PHP embed SAPI)include/php/ (PHP headers)Or install to one of the default fallback locations: ~/.ripht/php, ~/.local/php, or /usr/local.
Important Notes: This crate is focuses on the non-ZTS build of PHP. There aren't currently plans to support ZTS builds.
Tip: Tools like Static PHP CLI can simplify building PHP with the embed SAPI. See CONTRIBUTING.md for development setup options.
Add the crate to your Cargo.toml:
[dependencies]
ripht-php-sapi = "0.1.0-rc.5"
Example usage:
For convenience, the crate provides a prelude module — import it with use ripht_php_sapi::prelude::*; to get commonly used types.
Simulate an HTTP request. This populates $_GET, $_SERVER, etc.
use ripht_php_sapi::prelude::*;
let sapi = RiphtSapi::instance();
let script = std::path::Path::new("index.php");
let req = WebRequest::get()
.with_query_param("id", "123")
.with_header("User-Agent", "Ripht")
.build(&script)
.expect("build failed");
let res = sapi.execute(req).expect("execution failed");
assert_eq!(res.status_code(), 200);
println!("{}", res.body_string());
Use WebRequest::new() with any HTTP method. The Method enum implements TryFrom<&str>, making it easy to parse methods from incoming requests:
use ripht_php_sapi::prelude::*;
let sapi = RiphtSapi::instance();
let script = std::path::Path::new("api.php");
let method_str = "pUt";
let method = Method::try_from(method_str).expect("invalid method");
let req = WebRequest::new(method)
.with_uri("/users/42")
.with_content_type("application/json")
.with_body(r#"{"name": "Alice", "email": "alice@example.com"}"#)
.with_header("Authorization", "Bearer token123")
.build(&script)
.expect("build failed");
let res = sapi.execute(req).expect("execution failed");
println!("Status: {}", res.status_code());
println!("Response: {}", res.body_string());
Run a script as if from the command line. This sets argc/argv and avoids HTTP superglobals.
use ripht_php_sapi::prelude::*;
let sapi = RiphtSapi::instance();
let script = std::path::Path::new("script.php");
let req = CliRequest::new()
.with_arg("my-argument")
.with_env("MY_ENV_VAR", "value")
.build(&script)
.expect("build failed");
let res = sapi.execute(req).expect("execution failed");
println!("{}", res.body_string());
You only write safe Rust and don't have to worry about the low-level SAPI details.
Here's a minimal example that uses a single hook callback to stream output as it arrives:
use ripht_php_sapi::{RiphtSapi, WebRequest, ExecutionHooks, OutputAction};
struct StreamHooks;
impl ExecutionHooks for StreamHooks {
fn on_output(&mut self, data: &[u8]) -> OutputAction {
// Do something with the PHP output here...
OutputAction::Done
}
}
sapi.execute_with_hooks(ctx, StreamHooks).expect("execution failed");
lib/libphp.a (static embed SAPI) and headers. Set RIPHT_PHP_SAPI_PREFIX to point at your PHP build prefix if necessary..cargo/config.toml.example.The crate includes comprehensive examples demonstrating various use cases:
basic_execution.rs - Simple GET request handlingenv_and_ini.rs - Environment variables and INI overridespost_form.rs - Form data handlingpost_json.rs - JSON request processingfile_upload.rs - File upload handlinghooks_basic.rs - Basic hook implementationhooks_comprehensive.rs - Full hook lifecyclehooks_output_handling.rs - Output processinghooks_streaming_callback.rs - StreamingCallback helperstreaming_output.rs - Output streamingsession_handling.rs - PHP sessionshttp_server.rs - HTTP server integrationtracing_demo.rs - Observability integrationerror_handling.rs - Error managementexception_recovery.rs - Exception handlingmemory_pressure.rs - Memory usage testingfile_io.rs - File system operationsencoding_gaunlet.rs - Character encoding testsRun any example with:
cargo run --example <example_name>
Performance benchmarks are available in the benches/ directory:
sapi_comparison.rs - Compare against php-fpm and FrankenPHPthroughput.rs - Request throughput testingRun benchmarks with:
# Basic benchmarks
cargo bench --bench sapi_comparison
# External server comparison (requires setup)
BENCH_COMPARE=1 \
BENCH_FPM_BIN=/path/to/php-fpm \
BENCH_FRANKENPHP_BIN=/path/to/frankenphp \
cargo bench --bench sapi_comparison
For benchmark configuration and debug helpers, see .cargo/config.toml.example.
If you'd like to help, small and focused changes are appreciated.
MIT