php_sapi_name
Returns the lowercase name of the server API (SAPI) that PHP is currently running under.
php_sapi_name(): string|false- Added in PHP 4.0.1
Return value
string|falseThe interface type as a lowercase string, such as "cli", "fpm-fcgi", "cgi-fcgi", "apache2handler", "cli-server", "embed", "litespeed" or "phpdbg". Returns false on failure.
php_sapi_name() tells you which binding started the PHP process. The same script can run behind PHP-FPM, under the built-in web server, from a cron job, or inside a test runner, and this is how it finds out.
When to reach for it
The usual reason is output shape. Command line scripts want plain text and a real newline; web requests want HTML and headers. It is also the standard way to make a bootstrap file refuse to run: a maintenance or migration script can bail out immediately unless the SAPI is cli, so that nobody can trigger it by fetching the URL.
What trips people up
The strings are not the names you would guess. Apache's module SAPI reports apache2handler, not apache. PHP-FPM reports fpm-fcgi. The php -S development server reports cli-server, which is a web context even though the word cli is in it — a check like str_starts_with($sapi, 'cli') will wrongly treat it as a terminal script. Match the exact string 'cli' when you mean the command line.
The constant PHP_SAPI holds the same value and costs no function call, so most code can use it directly.
Example
When to use it
- Print plain text with newlines on the command line but HTML in a browser response.
- Make a database migration or seed script abort unless it was started from a terminal.
- Skip calls to header() or session_start() when the code is being exercised by a CLI test runner.
Frequently asked questions
What is the difference between php_sapi_name and PHP_SAPI?
There is none in value: PHP_SAPI is a constant holding exactly what php_sapi_name() returns. Use the constant in normal code since it avoids a function call and can be used in places that require a constant expression.
How do I check if a PHP script is running from the command line?
Compare the value to the exact string 'cli' — for example if (PHP_SAPI === 'cli'). Do not use a prefix match, because the built-in development server reports 'cli-server' and is serving real HTTP requests.
What does php_sapi_name return under PHP-FPM or Nginx?
It returns 'fpm-fcgi'. Nginx itself never appears in the value, because the SAPI describes how PHP was invoked, not which web server sits in front of it.
More examples
Guard a destructive script
Under the CLI binary the guard passes and the message prints. Served over HTTP by FPM or the built-in server the SAPI is not 'cli', so the script sends a 403 and exits before touching anything.
<?php
function assertCli(): void
{
if (php_sapi_name() !== 'cli') {
http_response_code(403);
exit("This script is command line only.\n");
}
}
assertCli();
echo "Safe to run the migration.\n";Choose the right line ending and escaping
On the CLI the text is printed raw with a newline. In a web SAPI the same call escapes the angle brackets and ampersand and appends a <br>, so one helper serves both contexts.
<?php
function out(string $text): void
{
if (PHP_SAPI === 'cli') {
echo $text, PHP_EOL;
return;
}
echo htmlspecialchars($text, ENT_QUOTES), '<br>', PHP_EOL;
}
out('Report for <admin> & team');
out('Done');Classify the SAPI into a category
The table makes the naming traps visible side by side: cli-server is classified as a web context despite its name, and both fpm-fcgi and cgi-fcgi land in the fastcgi bucket. The last row is whatever SAPI is actually running the snippet.
<?php
function sapiKind(string $sapi): string
{
return match (true) {
$sapi === 'cli', $sapi === 'phpdbg' => 'terminal',
$sapi === 'cli-server' => 'dev web server',
str_ends_with($sapi, 'fcgi') => 'fastcgi web',
default => 'other web',
};
}
foreach (['cli', 'cli-server', 'fpm-fcgi', 'apache2handler', php_sapi_name()] as $s) {
printf("%-15s => %s\n", $s, sapiKind($s));
}
Discussion