はじめに
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アプリケーションを開発しましょう!
参考リンク
この記事が役に立ったら、ぜひシェアしてください!
