Skip to content

Instantly share code, notes, and snippets.

@masakielastic
Last active February 27, 2026 04:52
Show Gist options
  • Select an option

  • Save masakielastic/444e996abf337cd2bb8bc0604324215b to your computer and use it in GitHub Desktop.

Select an option

Save masakielastic/444e996abf337cd2bb8bc0604324215b to your computer and use it in GitHub Desktop.
ripht-php-sapi で PHP スクリプトを実行する CLI ツールを開発する

ripht-php-sapi で PHP スクリプトを実行する CLI ツールを開発する

コード

Cargo.toml

[package]
name = "php-run"
version = "0.1.0"
edition = "2021"

[dependencies]
ripht-php-sapi = "0.1.0-rc.7"
clap = { version = "4.5", features = ["derive"] }
anyhow = "1.0"

src/main.rs

use anyhow::{anyhow, Context, Result};
use clap::Parser;
use ripht_php_sapi::prelude::*;
use std::path::PathBuf;

#[derive(Parser, Debug)]
#[command(name = "php-run", about = "Run a PHP script via ripht_php_sapi (embed SAPI)")]

struct Cli {
    /// Path to the PHP script to execute
    script: PathBuf,

    /// Environment variables to inject (KEY=VALUE). You can repeat this flag.
    #[arg(long = "env", value_parser = parse_kv)]
    env: Vec<(String, String)>,

    /// PHP argv entries passed to the script.
    /// Use `--` to separate php-run args from script args, e.g.:
    ///   php-run script.php -- a b c
    #[arg(trailing_var_arg = true)]
    args: Vec<String>,
}

fn parse_kv(s: &str) -> Result<(String, String), String> {
    let (k, v) = s
        .split_once('=')
        .ok_or_else(|| "expected KEY=VALUE".to_string())?;
    if k.is_empty() {
        return Err("KEY must be non-empty".to_string());
    }
    Ok((k.to_string(), v.to_string()))
}

fn main() -> Result<()> {
    let cli = Cli::parse();

    // 1) Initialize SAPI once
    let sapi = RiphtSapi::instance();

    // 2) Build a CLI request for the script
    let mut builder = CliRequest::new();

    // Pass args to PHP as $argv entries.
    // (ripht_php_sapi side will also populate the usual CLI superglobals automatically.)
    builder = builder.with_args(cli.args);

    // Inject environment variables (optional)
    builder = builder.with_envs(cli.env);

    let req = builder
        .build(&cli.script)
        .map_err(|e| anyhow!("build failed: {e:?}"))
        .with_context(|| format!("script path: {}", cli.script.display()))?;

    // 3) Execute
    let res = sapi
        .execute(req)
        .map_err(|e| anyhow!("execution failed: {e:?}"))?;

    // 4) Print stdout-equivalent body (what the script echoed/printed)
    print!("{}", res.body_string());

    // 任意: 終了ステータスを HTTP 的に扱いたい場合などは res.status_code() も参照できます
    // eprintln!("status={}", res.status_code());

    Ok(())
}

ビルドと実行

test.php

<?php
var_dump(PHP_SAPI);
var_dump(ini_get('register_argc_argv'));
var_dump($_SERVER['argc'] ?? null);
var_dump($_SERVER['argv'] ?? null);
target/debug/php-run test.php
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment