Skip to content

jhavenz/ripht-php-sapi

Repository files navigation

ripht-php-sapi

Crates.io docs.rs License: MIT

Safe, pragmatic Rust bindings for embedding PHP via the embed SAPI.

Why ripht-php-sapi?

  1. Provide tooling that will allow additional PHP tooling to be built in Rust.

  2. I hadn't seen another Rust crate offering comparable features.

  3. I'm planning to build more tooling on this (stay tuned...).

Requirements

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.

Quick start

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.

Web Example

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());

PUT Method Example

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());

CLI Example

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");

Development notes

  • The build script expects a PHP build root that contains lib/libphp.a (static embed SAPI) and headers. Set RIPHT_PHP_SAPI_PREFIX to point at your PHP build prefix if necessary.
  • Example debug/run helpers and bench configuration are in .cargo/config.toml.example.

Examples

The crate includes comprehensive examples demonstrating various use cases:

Run any example with:

cargo run --example <example_name>

Benchmarking

Performance benchmarks are available in the benches/ directory:

Standard Benchmarks

Run 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.

Support My Work

Contributing

If you'd like to help, small and focused changes are appreciated.

License

MIT

About

A PHP SAPI written in Rust to expose safe and convenient apis to encourage additional Rust tooling development for PHP

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Sponsor this project

Packages

 
 
 

Contributors