ripht-php-sapi 0.1.0-rc.3

Ripht PHP SAPI - A PHP SAPI written in Rust to expose safe and convenient APIs to encourage additional Rust tooling development for PHP
Documentation
# Ripht PHP SAPI

Safe, pragmatic Rust bindings to PHP's Server API (SAPI) for embedding PHP into Rust applications.

The goal: provide a convenience layer to encourage development of additional Rust tooling for PHP.

## Requirements

This crate requires PHP built with the embed SAPI as a static library:

```bash
./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`.

> **Tip**: Tools like [Static PHP CLI]https://github.com/crazywhalecc/static-php-cli can simplify building PHP with the embed SAPI. See [CONTRIBUTING.md]CONTRIBUTING.md for development setup options.

## Quick start

Add the crate to your `Cargo.toml`:

```toml
[dependencies]
ripht-php-sapi = "0.1.0-rc.3"
```

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.

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

### CLI Example

Run a script as if from the command line. This sets `argc`/`argv` and avoids HTTP superglobals.

```rust
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:

```rust
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::Handled
    }
}

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`.
- Benchmarks use Criterion and live under `benches/`. Run them with:

```bash
cargo bench --bench sapi_comparison
```

To compare against external servers (php-fpm/FrankenPHP), set environment variables before running the bench, e.g.:

_Note: you'll need to have the frankenphp and php-fpm builds setup before running this. Reach out if you have questions_

```bash
BENCH_COMPARE=1 \
    BENCH_FPM_BIN=/path/to/php-fpm \
    BENCH_FRANKENPHP_BIN=/path/to/frankenphp \
    cargo bench --bench sapi_comparison
```

## Examples

See `examples/` and `tests/php_scripts/` for sample usage and test scripts.

## Learning Material

Building this SAPI required diving deep into PHP internals, Rust FFI, and the patterns that connect them. I'm working on educational material to share what I've discovered along the way.

In building this crate, there was quite a bit research material to aggregate. 

If you're like me, interested in learning & knowing all layers of a PHP application, please let me know [here](https://www.patreon.com/posts/gauging-php-sapi-146489023) (I'm debating writing some educational material).

## Support

Support on [Patreon](https://patreon.com/jhavenz) is be greatly appreciated.


## Contributing

If you'd like to help, open an issue or a PR — small, focused changes are appreciated.

## License

MIT