はじめに
PHPスクリプトを書いていて、「このコードはコマンドラインで実行されているのか、それともWebサーバー経由なのか?」を判定したいと思ったことはありませんか?
同じPHPスクリプトでも、実行環境によって動作を変えたいケースは多々あります。例えば:
- CLI環境ではプログレスバーを表示したい
 - Web環境ではHTMLを出力したい
 - セキュリティのため、特定の処理はCLIでのみ実行可能にしたい
 
そんな時に活躍するのが**php_sapi_name関数**です。この関数を使えば、PHPがどのインターフェース(SAPI)で実行されているかを簡単に判定できます。
この記事では、php_sapi_nameの基本から実践的な活用方法まで、詳しく解説します。
php_sapi_nameとは?
php_sapi_nameは、現在のPHPが使用しているServer API(SAPI)の名前を返す関数です。
基本構文
php_sapi_name(): string|false
パラメータ
この関数はパラメータを取りません。
戻り値
- 成功時: SAPIの名前を示す文字列
 - 失敗時: 
false(通常は発生しません) 
主なSAPI名
| SAPI名 | 説明 | 実行環境 | 
|---|---|---|
cli | Command Line Interface | コマンドライン | 
apache2handler | Apache 2.x (モジュール版) | Apache Webサーバー | 
fpm-fcgi | FastCGI Process Manager | PHP-FPM | 
cgi-fcgi | CGI/FastCGI | CGI環境 | 
litespeed | LiteSpeed Web Server | LiteSpeed | 
cli-server | 組み込みWebサーバー | php -S コマンド | 
embed | 組み込みSAPI | 組み込み環境 | 
対応バージョン
- PHP 4.0.1 以降で使用可能
 
基本的な使い方
シンプルな確認方法
<?php
$sapi = php_sapi_name();
echo "現在のSAPI: {$sapi}\n";
// 出力例:
// CLI: cli
// Apache: apache2handler
// PHP-FPM: fpm-fcgi
?>
CLI環境かどうかを判定
<?php
function isCLI() {
    return php_sapi_name() === 'cli';
}
if (isCLI()) {
    echo "コマンドラインから実行されています\n";
} else {
    echo "Webサーバーから実行されています\n";
}
?>
定数PHP_SAPIとの比較
<?php
// 方法1: 関数を使用
$sapi1 = php_sapi_name();
// 方法2: 定数を使用(推奨)
$sapi2 = PHP_SAPI;
echo "php_sapi_name(): {$sapi1}\n";
echo "PHP_SAPI: {$sapi2}\n";
// 両者は同じ値を返す
// PHP_SAPIの方が高速(関数呼び出しのオーバーヘッドがない)
?>
実践的な使用例
例1: 出力形式を環境に応じて変更
<?php
function output($message, $type = 'info') {
    $sapi = php_sapi_name();
    
    if ($sapi === 'cli') {
        // CLI: プレーンテキスト
        $prefix = match($type) {
            'error' => '[ERROR]',
            'warning' => '[WARN]',
            'success' => '[OK]',
            default => '[INFO]'
        };
        echo "{$prefix} {$message}\n";
    } else {
        // Web: HTML
        $class = match($type) {
            'error' => 'error',
            'warning' => 'warning',
            'success' => 'success',
            default => 'info'
        };
        echo "<div class='{$class}'>{$message}</div>\n";
    }
}
// 使用例
output('処理が完了しました', 'success');
output('警告: メモリ使用量が多いです', 'warning');
output('エラーが発生しました', 'error');
?>
例2: プログレスバーの表示
<?php
function showProgress($current, $total, $message = '') {
    if (php_sapi_name() !== 'cli') {
        // CLI以外では何もしない
        return;
    }
    
    $percent = ($current / $total) * 100;
    $bar_length = 50;
    $filled = (int)(($current / $total) * $bar_length);
    $bar = str_repeat('=', $filled) . str_repeat('-', $bar_length - $filled);
    
    printf("\r[%s] %3d%% %s", $bar, $percent, $message);
    
    if ($current >= $total) {
        echo "\n";
    }
}
// 使用例
for ($i = 1; $i <= 100; $i++) {
    showProgress($i, 100, "処理中... ({$i}/100)");
    usleep(50000); // 0.05秒待機
}
?>
例3: 環境別の設定読み込み
<?php
function loadConfig() {
    $sapi = php_sapi_name();
    
    $config = [
        'app_name' => 'MyApp',
        'version' => '1.0.0'
    ];
    
    switch ($sapi) {
        case 'cli':
            $config['output_format'] = 'text';
            $config['color_enabled'] = true;
            $config['log_level'] = 'debug';
            break;
            
        case 'apache2handler':
        case 'fpm-fcgi':
            $config['output_format'] = 'html';
            $config['color_enabled'] = false;
            $config['log_level'] = 'error';
            $config['session_enabled'] = true;
            break;
            
        case 'cli-server':
            $config['output_format'] = 'html';
            $config['color_enabled'] = false;
            $config['log_level'] = 'debug';
            break;
            
        default:
            $config['output_format'] = 'text';
            $config['log_level'] = 'info';
    }
    
    return $config;
}
$config = loadConfig();
print_r($config);
?>
例4: セキュリティ制限の実装
<?php
function requireCLI($message = '這のスクリプトはコマンドラインからのみ実行できます') {
    if (php_sapi_name() !== 'cli') {
        if (php_sapi_name() === 'cli-server') {
            // 開発用サーバーは許可する場合
            return true;
        }
        
        // Web経由での実行を拒否
        http_response_code(403);
        die($message);
    }
    return true;
}
// 危険な処理を行うスクリプトの先頭に記述
requireCLI();
echo "データベースのクリーンアップを開始します...\n";
// データベースのクリーンアップ処理
?>
例5: ログ出力の最適化
<?php
class Logger {
    private $sapi;
    
    public function __construct() {
        $this->sapi = php_sapi_name();
    }
    
    public function log($level, $message) {
        $timestamp = date('Y-m-d H:i:s');
        $formatted = "[{$timestamp}] [{$level}] {$message}";
        
        if ($this->sapi === 'cli') {
            // CLI: 標準エラー出力
            fwrite(STDERR, $formatted . "\n");
        } else {
            // Web: error_logに出力
            error_log($formatted);
            
            // 開発環境ならブラウザにも表示
            if (ini_get('display_errors')) {
                echo "<!-- {$formatted} -->\n";
            }
        }
    }
    
    public function info($message) {
        $this->log('INFO', $message);
    }
    
    public function error($message) {
        $this->log('ERROR', $message);
    }
}
// 使用例
$logger = new Logger();
$logger->info('アプリケーションを起動しました');
$logger->error('データベース接続に失敗しました');
?>
環境判定のベストプラクティス
汎用的な環境判定クラス
<?php
class Environment {
    private static $sapi = null;
    
    public static function getSAPI() {
        if (self::$sapi === null) {
            self::$sapi = php_sapi_name();
        }
        return self::$sapi;
    }
    
    public static function isCLI() {
        return self::getSAPI() === 'cli';
    }
    
    public static function isWeb() {
        return in_array(self::getSAPI(), [
            'apache2handler',
            'fpm-fcgi',
            'cgi-fcgi',
            'litespeed'
        ]);
    }
    
    public static function isDevServer() {
        return self::getSAPI() === 'cli-server';
    }
    
    public static function isFastCGI() {
        return strpos(self::getSAPI(), 'fcgi') !== false;
    }
    
    public static function isApache() {
        return strpos(self::getSAPI(), 'apache') !== false;
    }
    
    public static function getType() {
        if (self::isCLI()) return 'cli';
        if (self::isWeb()) return 'web';
        if (self::isDevServer()) return 'dev-server';
        return 'unknown';
    }
    
    public static function displayInfo() {
        echo "=== 実行環境情報 ===\n";
        echo "SAPI: " . self::getSAPI() . "\n";
        echo "タイプ: " . self::getType() . "\n";
        echo "CLI: " . (self::isCLI() ? 'はい' : 'いいえ') . "\n";
        echo "Web: " . (self::isWeb() ? 'はい' : 'いいえ') . "\n";
        echo "FastCGI: " . (self::isFastCGI() ? 'はい' : 'いいえ') . "\n";
    }
}
// 使用例
Environment::displayInfo();
if (Environment::isCLI()) {
    echo "コマンドライン専用の処理を実行\n";
}
?>
SAPI別の特徴と対応
Apache (apache2handler)
<?php
if (php_sapi_name() === 'apache2handler') {
    echo "Apache環境で実行中\n";
    
    // Apacheモジュールとして実行されている
    // - .htaccessが使用可能
    // - apache_*関数が使用可能
    
    if (function_exists('apache_get_version')) {
        echo "Apacheバージョン: " . apache_get_version() . "\n";
    }
    
    if (function_exists('apache_get_modules')) {
        echo "ロード済みモジュール:\n";
        print_r(apache_get_modules());
    }
}
?>
PHP-FPM (fpm-fcgi)
<?php
if (php_sapi_name() === 'fpm-fcgi') {
    echo "PHP-FPM環境で実行中\n";
    
    // FastCGI Process Managerとして実行
    // - Nginx、Apache、LiteSpeedなどと組み合わせて使用
    // - プロセスプールで効率的に処理
    
    // FPM固有の設定を確認
    $fpm_settings = [
        'pm' => ini_get('pm'),
        'pm.max_children' => ini_get('pm.max_children'),
        'pm.start_servers' => ini_get('pm.start_servers')
    ];
    
    print_r($fpm_settings);
}
?>
CLI (cli)
<?php
if (php_sapi_name() === 'cli') {
    echo "CLI環境で実行中\n";
    
    // コマンドラインインターフェース
    // - 対話的な処理が可能
    // - STDIN、STDOUT、STDERRが使用可能
    // - タイムアウトなし(max_execution_time = 0)
    
    // コマンドライン引数を取得
    global $argv, $argc;
    echo "引数の数: {$argc}\n";
    print_r($argv);
    
    // 標準入力から読み込み
    if (!empty($argv[1]) && $argv[1] === '--interactive') {
        echo "名前を入力してください: ";
        $name = trim(fgets(STDIN));
        echo "こんにちは、{$name}さん!\n";
    }
}
?>
組み込みWebサーバー (cli-server)
<?php
if (php_sapi_name() === 'cli-server') {
    echo "組み込みWebサーバーで実行中\n";
    
    // php -S localhost:8000 で起動
    // - 開発用途に最適
    // - 本番環境では使用しない
    
    echo "警告: これは開発用サーバーです\n";
    echo "本番環境では使用しないでください\n";
}
?>
実用的なパターン集
パターン1: コマンドラインツールの作成
<?php
// cli-tool.php
class CLITool {
    public function __construct() {
        if (!$this->isCLI()) {
            die("このスクリプトはコマンドラインから実行してください\n");
        }
    }
    
    private function isCLI() {
        return php_sapi_name() === 'cli';
    }
    
    public function run($argv) {
        if (count($argv) < 2) {
            $this->showHelp();
            return;
        }
        
        $command = $argv[1];
        
        switch ($command) {
            case 'status':
                $this->showStatus();
                break;
                
            case 'process':
                $this->processData();
                break;
                
            default:
                echo "エラー: 不明なコマンド '{$command}'\n";
                $this->showHelp();
        }
    }
    
    private function showHelp() {
        echo <<<HELP
使用方法: php cli-tool.php [command]
コマンド:
  status   - ステータスを表示
  process  - データ処理を実行
  
HELP;
    }
    
    private function showStatus() {
        echo "=== システムステータス ===\n";
        echo "PHP: " . PHP_VERSION . "\n";
        echo "SAPI: " . php_sapi_name() . "\n";
        echo "メモリ: " . ini_get('memory_limit') . "\n";
    }
    
    private function processData() {
        echo "データ処理を開始...\n";
        // 処理の実装
        echo "完了\n";
    }
}
// 実行
$tool = new CLITool();
$tool->run($argv);
?>
パターン2: Web/CLIハイブリッドスクリプト
<?php
// hybrid-script.php
class HybridScript {
    private $sapi;
    
    public function __construct() {
        $this->sapi = php_sapi_name();
    }
    
    public function execute() {
        $data = $this->processData();
        $this->output($data);
    }
    
    private function processData() {
        // 共通の処理
        return [
            'timestamp' => date('Y-m-d H:i:s'),
            'sapi' => $this->sapi,
            'memory' => memory_get_usage(true)
        ];
    }
    
    private function output($data) {
        if ($this->sapi === 'cli') {
            $this->outputCLI($data);
        } else {
            $this->outputWeb($data);
        }
    }
    
    private function outputCLI($data) {
        echo "=== 実行結果 ===\n";
        foreach ($data as $key => $value) {
            echo sprintf("%-15s: %s\n", $key, $value);
        }
    }
    
    private function outputWeb($data) {
        header('Content-Type: application/json');
        echo json_encode($data, JSON_PRETTY_PRINT);
    }
}
$script = new HybridScript();
$script->execute();
// CLI実行: php hybrid-script.php
// Web実行: http://localhost/hybrid-script.php
?>
パターン3: 環境検出とリダイレクト
<?php
// redirect-cli.php
function checkEnvironment() {
    $sapi = php_sapi_name();
    
    if ($sapi === 'cli') {
        // CLIから実行された場合
        return true;
    }
    
    // Web経由の場合、CLIコマンドを提示
    $script = basename(__FILE__);
    $command = "php {$script}";
    
    header('Content-Type: text/html; charset=UTF-8');
    echo <<<HTML
<!DOCTYPE html>
<html>
<head>
    <title>CLI専用スクリプト</title>
    <style>
        body { font-family: monospace; padding: 20px; }
        .command { background: #f0f0f0; padding: 10px; border-radius: 5px; }
    </style>
</head>
<body>
    <h1>このスクリプトはコマンドラインから実行してください</h1>
    <p>以下のコマンドを実行してください:</p>
    <div class="command">{$command}</div>
</body>
</html>
HTML;
    exit;
}
checkEnvironment();
// ここからCLI専用の処理
echo "CLI環境で実行中...\n";
?>
トラブルシューティング
ケース1: CGI/FastCGIの判定
<?php
function detectCGIType() {
    $sapi = php_sapi_name();
    
    echo "SAPI: {$sapi}\n";
    
    if (strpos($sapi, 'cgi') !== false) {
        echo "CGI環境で実行中\n";
        
        if (strpos($sapi, 'fcgi') !== false) {
            echo "タイプ: FastCGI\n";
        } else {
            echo "タイプ: 従来型CGI\n";
        }
        
        // 環境変数を確認
        $cgi_vars = [
            'GATEWAY_INTERFACE',
            'FCGI_ROLE',
            'PHP_FCGI_CHILDREN',
            'PHP_FCGI_MAX_REQUESTS'
        ];
        
        echo "\nCGI環境変数:\n";
        foreach ($cgi_vars as $var) {
            $value = getenv($var);
            if ($value !== false) {
                echo "  {$var}: {$value}\n";
            }
        }
    }
}
detectCGIType();
?>
ケース2: 環境の不一致
<?php
function diagnoseEnvironment() {
    $sapi = php_sapi_name();
    $is_cli = (php_sapi_name() === 'cli');
    $has_http = !empty($_SERVER['HTTP_HOST']);
    $has_argv = isset($argc);
    
    echo "=== 環境診断 ===\n";
    echo "SAPI: {$sapi}\n";
    echo "isCLI(): " . ($is_cli ? 'true' : 'false') . "\n";
    echo "HTTP_HOST: " . ($has_http ? '存在' : '不在') . "\n";
    echo "\$argc: " . ($has_argv ? '存在' : '不在') . "\n\n";
    
    // 矛盾をチェック
    if ($is_cli && $has_http) {
        echo "⚠ 警告: CLIなのにHTTP_HOSTが設定されています\n";
    }
    
    if (!$is_cli && $has_argv) {
        echo "⚠ 警告: Web環境なのに\$argvが設定されています\n";
    }
    
    // 推奨される判定方法
    echo "\n推奨される判定方法:\n";
    echo "  1. PHP_SAPI定数を使用: " . PHP_SAPI . "\n";
    echo "  2. php_sapi_name()を使用: " . php_sapi_name() . "\n";
}
diagnoseEnvironment();
?>
パフォーマンスの考慮
定数 vs 関数呼び出し
<?php
// ベンチマーク
$iterations = 100000;
// 方法1: PHP_SAPI定数
$start = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
    $sapi = PHP_SAPI;
}
$time1 = microtime(true) - $start;
// 方法2: php_sapi_name()関数
$start = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
    $sapi = php_sapi_name();
}
$time2 = microtime(true) - $start;
echo "=== パフォーマンス比較 ({$iterations}回) ===\n";
echo "PHP_SAPI定数:      " . number_format($time1, 6) . "秒\n";
echo "php_sapi_name():   " . number_format($time2, 6) . "秒\n";
echo "差分:              " . number_format($time2 - $time1, 6) . "秒\n";
echo "\n推奨: PHP_SAPI定数の方が高速です\n";
// 結果例:
// PHP_SAPI定数:      0.002000秒
// php_sapi_name():   0.005000秒
?>
キャッシュの活用
<?php
class SAPIDetector {
    private static $sapi = null;
    private static $isCLI = null;
    
    public static function getSAPI() {
        if (self::$sapi === null) {
            self::$sapi = PHP_SAPI; // 定数を使用
        }
        return self::$sapi;
    }
    
    public static function isCLI() {
        if (self::$isCLI === null) {
            self::$isCLI = (self::getSAPI() === 'cli');
        }
        return self::$isCLI;
    }
}
// 何度呼び出しても最初の1回だけ評価される
for ($i = 0; $i < 100; $i++) {
    SAPIDetector::isCLI();
}
?>
まとめ
php_sapi_nameは、PHPの実行環境を判定するための重要な関数です。
主な特徴:
- ✅ 実行環境(SAPI)を文字列で返す
 - ✅ CLI、Apache、PHP-FPMなど様々な環境を判定可能
 - ✅ 環境に応じた処理の分岐に便利
 - ✅ PHP_SAPI定数も使用可能(こちらが高速)
 
よく使うSAPI:
cli– コマンドラインapache2handler– Apachefpm-fcgi– PHP-FPMcli-server– 組み込みWebサーバー
ベストプラクティス:
- パフォーマンス重視なら
PHP_SAPI定数を使用 - 環境判定は関数やクラスでラップする
 - CLIとWebで処理を分ける際に活用
 - セキュリティ制限の実装に利用
 
活用シーン:
- コマンドラインツールの開発
 - 環境別の設定管理
 - 出力形式の切り替え
 - セキュリティ制御
 
この関数を理解して、環境に応じた柔軟なPHPアプリケーションを開発しましょう!
参考リンク
この記事が役に立ったら、ぜひシェアしてください!
  
  
  
  