CGI/FastCGI SAPI12 min read

PHP CGI and FastCGI: how the CGI SAPI fits in

A cautious, source-limited look at PHP's CGI build, how it differs from the CLI, and why FastCGI and FPM need separate evidence and must never be exposed publicly.

PHP compatibility and project lifecycle

Unknown from the supplied source. The page does not state PHP version compatibility, deprecations or support status. The example uses only core PHP features.

Official sources checked 2026-10-22. Browser lessons on this site run PHP 8.5.

What this project is

This guide covers the CGI side of PHP's server-facing interfaces. The only official source supplied is the PHP manual page titled "CGI and command line setups". That page says that by default PHP is built as both a CLI program and a CGI program, and that the CGI program can be used for CGI processing.

This is part of PHP core. It is not a framework, a CMS, an async library, a framework adapter or a historical alternative interpreter. It is a way of running the same language engine. Drupal, for example, is a CMS product built on PHP and is a different kind of thing. Swoole and Open Swoole are likewise separate projects from PHP core, and this guide does not cover either.

The lifecycle status of this topic is unknown for this guide. The supplied page does not give version numbers, deprecation status, support windows or PHP 8.4 or 8.5 compatibility statements. None are asserted here. The learning track stays on PHP 8.4, with PHP 8.5 planned.

What the source says

The page makes four points:

  • A default PHP build produces both a CLI program and a CGI program.
  • If your web server has module support for PHP, the manual says you should generally prefer that for performance reasons.
  • The CGI version lets users run different PHP-enabled pages under different user IDs.
  • A server deployed in CGI mode is open to several possible vulnerabilities, and the manual points readers to its CGI security section.

The page also says you can test a CGI build with make test. It lists the variables defined by the CGI/1.1 specification: AUTH_TYPE, CONTENT_LENGTH, CONTENT_TYPE, GATEWAY_INTERFACE, PATH_INFO, PATH_TRANSLATED, QUERY_STRING, REMOTE_ADDR, REMOTE_HOST, REMOTE_IDENT, REMOTE_USER, REQUEST_METHOD, SCRIPT_NAME, SERVER_NAME, SERVER_PORT, SERVER_PROTOCOL and SERVER_SOFTWARE. Anything else a server supplies should be treated as a vendor extension.

Architecture and execution model

In the CGI model, a web server hands request data to a PHP program through the CGI/1.1 interface, mostly as environment variables such as REQUEST_METHOD and QUERY_STRING. PHP runs the script and returns the output to the server. The CLI build is a separate program from the same default build, meant for the command line rather than a web server.

The classic request lifetime is: a request arrives, PHP runs the script, the response is produced, and per-request state is discarded. Nothing in the supplied page describes a long-lived worker.

FastCGI and FPM: what the source does not cover

The assignment asks for a distinction between the CGI binary, FastCGI and FPM. The supplied page does not mention FastCGI or FPM at all. This guide therefore makes no detailed claims about how FastCGI processes are managed, how many requests a process serves, or how FPM is configured. Those points are unknown here and need an additional official source before this guide is finalised.

The following conservative framing is all this guide commits to:

  • The CGI binary is the program the supplied page describes.
  • FastCGI and FPM are treated as separate topics that require their own evidence.
  • A FastCGI endpoint is an internal interface between a web server and PHP. It must never be published on a public network interface. Keep it on a private socket or a loopback address, and let only the web server reach it.

Persistent workers and state leakage

A classic request lifetime clears per-request state when the request ends. A persistent worker, meaning any setup where one PHP process serves many requests, can carry state from one request to the next. Whether any FastCGI setup behaves this way is not stated in the supplied source, so treat it as unknown and verify it.

If you do run a long-lived process, plan for state leakage:

  • Static properties, global variables and singletons can keep one user's data alive for the next request.
  • Open connections, caches and file handles can outlive the request that created them.
  • Request-scoped data, such as the current user, must be reset explicitly.

Cleanup means resetting or discarding request-scoped state at the end of every request, avoiding mutable global state, and testing that two consecutive requests cannot see each other's data. Do not assume a framework or adapter does this for you without reading its documentation.

Practical use cases

  • Learning how a web server communicates with PHP through the CGI/1.1 variables.
  • Understanding the manual's point that CGI can run different pages under different user IDs.
  • Inspecting which SAPI a script is running under while debugging environment differences.

For most new web work, the manual recommends a module-based integration where your server supports one. Choosing between CGI, FastCGI and FPM needs more evidence than this guide has.

Installation approach

The page says a default PHP build produces both the CLI and CGI programs, and that you can verify a build with make test. The packet does not give configure flags, package names, binary names or distribution-specific steps, so none are invented. Use your platform's official PHP documentation for installation, and check that the PHP you run reports version 8.4 for this track.

Strengths

  • The CGI model is simple to reason about, because request data arrives through documented CGI/1.1 variables.
  • According to the manual, it allows different PHP-enabled pages to run under different user IDs.
  • It ships with a default build, so no separate project is needed.

Limitations

  • The manual warns that a server deployed in CGI mode is open to several possible vulnerabilities and points to its CGI security section. Read that section before any deployment.
  • The manual suggests module support for performance reasons. This guide makes no speed claims of its own.
  • Version support, deprecation status and licensing are unknown from this source.
  • Variables outside the CGI/1.1 list are vendor extensions and should not be relied on blindly.

Deployment notes

No Docker Compose example is given, because the supplied source does not support one. If you deploy anything FastCGI-related, bind development ports to 127.0.0.1 only, keep FastCGI off public interfaces, and put a web server in front. Run the process under a least-privilege user. Review the manual's CGI security section and have a human check your configuration.

The example

The example is a single script that reports the active SAPI and which of the CGI/1.1 variables are present in the server array. It needs no Composer packages and no network service. Because it runs from the command line, it is not a browser exercise.

Further reading

The only official source for this guide is the PHP manual page linked below.

Practical examples

These examples have not been run in a live environment yet. Commands and versions follow the official documentation linked on this page; check them before relying on them, and report a problem if one does not work.

Inspect the SAPI and CGI/1.1 variables with core PHP

A single dependency-free script that reports PHP_SAPI and which CGI/1.1 variables from the manual are present in the server array. It is written for PHP 8.4 and is run here from the CLI. Behaviour under a CGI setup is not shown.

public/cgi-vars.php

<?php

declare(strict_types=1);

// Variables defined by the CGI/1.1 specification, as listed in the PHP manual page.
const CGI_11_VARIABLES = [
    'AUTH_TYPE',
    'CONTENT_LENGTH',
    'CONTENT_TYPE',
    'GATEWAY_INTERFACE',
    'PATH_INFO',
    'PATH_TRANSLATED',
    'QUERY_STRING',
    'REMOTE_ADDR',
    'REMOTE_HOST',
    'REMOTE_IDENT',
    'REMOTE_USER',
    'REQUEST_METHOD',
    'SCRIPT_NAME',
    'SERVER_NAME',
    'SERVER_PORT',
    'SERVER_PROTOCOL',
    'SERVER_SOFTWARE',
];

$present = [];
$missing = [];

foreach (CGI_11_VARIABLES as $name) {
    if (isset($_SERVER[$name])) {
        $present[] = $name;
    } else {
        $missing[] = $name;
    }
}

$report = [
    'sapi' => PHP_SAPI,
    'php_version' => PHP_VERSION,
    'cgi_1_1_present' => $present,
    'cgi_1_1_missing' => $missing,
];

if (PHP_SAPI !== 'cli' && !headers_sent()) {
    header('Content-Type: application/json');
}

echo json_encode($report, JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR), PHP_EOL;

Install and run

php -v
php public/cgi-vars.php

Expected behavior

Run from the command line, the script prints a JSON report. The sapi field is expected to be cli, php_version should show the installed 8.4 release, and most CGI/1.1 variables are expected to appear under cgi_1_1_missing because no web server supplied them.

Requires PHP 8.4 on the command line and no other dependencies. It does not start a CGI or FastCGI server, does not demonstrate FPM, and does not show request-to-request state. It is not a browser exercise.