lisachenko / protocol-fcgi
Implementation of the FastCGI (FCGI) protocol in PHP
Fund package maintenance!
Requires
- php: >=8.4
Requires (Dev)
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^12.2
This package is auto-updated.
Last update: 2026-07-31 08:46:50 UTC
README
A zero-dependency, object-oriented implementation of the FastCGI 1.0 binary protocol for PHP.
FastCGI is the battle-tested protocol that web servers like nginx, Apache and Caddy use to
talk to php-fpm â billions of requests flow through it every day. This library gives you
the protocol itself as a clean, strictly-typed PHP API, so you can build your own
high-performance FastCGI clients (talk to php-fpm directly, no web server in between)
and servers (long-running PHP daemons that nginx can speak to natively).
âĻ Key Features
- ðĶ Complete protocol coverage â all 11 FastCGI record types, including the
management records (
GET_VALUES,GET_VALUES_RESULT,UNKNOWN_TYPE) - ð Streaming frame parser â feed partial socket reads into
FrameParser::hasFrame()/parseFrame()and get fully-typed record objects out as soon as they are complete - ð Byte-exact round-tripping â every record packs back to the exact wire bytes it was parsed from; the test suite is pinned to hex fixtures captured from real traffic
- ð Automatic 8-byte padding â content alignment is handled for you, as the spec recommends
- ð·ïļ Full name-value pair encoding â including the 4-byte long form for names and values over 127 bytes
- ðŊ Native enums for the protocol vocabulary â record types, roles and protocol
statuses are backed enums (
RecordType,Role,ProtocolStatus), so invalid wire values fail fast with a dedicatedProtocolException - ðŠķ Zero runtime dependencies â pure PHP, nothing but the language itself
- ð Strict types + PHPStan at the maximum level â the whole codebase (tests included) passes static analysis at the strictest setting
Requirements
- PHP >= 8.4
Installation
composer require lisachenko/protocol-fcgi
Usage
The library implements both sides of the wire: use it to send FastCGI requests as a client, or to receive and answer them as a server. The full protocol specification is available at fast-cgi.github.io/spec.
FastCGI client: query php-fpm directly
<?php use Lisachenko\Protocol\FCGI\FrameParser; use Lisachenko\Protocol\FCGI\Record\BeginRequest; use Lisachenko\Protocol\FCGI\Record\EndRequest; use Lisachenko\Protocol\FCGI\Record\Params; use Lisachenko\Protocol\FCGI\Record\Stdin; use Lisachenko\Protocol\FCGI\Record\Stdout; use Lisachenko\Protocol\FCGI\Role; include 'vendor/autoload.php'; // Connect to the local php-fpm daemon directly $phpSocket = fsockopen('127.0.0.1', 9001, $errorNumber, $errorString); // Prepare the request: begin, pass parameters, then close the input stream. // Empty Params and Stdin records mark the end of the corresponding stream. $packet = ''; $packet .= new BeginRequest(Role::Responder); $packet .= new Params(['SCRIPT_FILENAME' => '/var/www/some_file.php']); $packet .= new Params([]); $packet .= new Stdin(''); fwrite($phpSocket, $packet); // Read the response incrementally: the parser consumes complete frames // from the buffer and leaves partial ones for the next read. $buffer = ''; while ($partialData = fread($phpSocket, 4096)) { $buffer .= $partialData; while (FrameParser::hasFrame($buffer)) { $record = FrameParser::parseFrame($buffer); if ($record instanceof Stdout) { echo $record->getContentData(); } if ($record instanceof EndRequest) { break 2; // response is complete } } } fclose($phpSocket);
FastCGI server: accept requests from a web server
<?php use Lisachenko\Protocol\FCGI\FrameParser; include 'vendor/autoload.php'; $server = stream_socket_server('tcp://127.0.0.1:9001', $errorNumber, $errorString); // Accept one connection and parse everything the web server sends $socket = stream_socket_accept($server); $buffer = ''; while ($partialData = fread($socket, 4096)) { $buffer .= $partialData; while (FrameParser::hasFrame($buffer)) { $record = FrameParser::parseFrame($buffer); var_dump($record); // BeginRequest, Params, Stdin, ... } } // Answering (Stdout + EndRequest records) is up to your application fclose($socket); fclose($server);
Quality
composer test # PHPUnit test suite composer phpstan # PHPStan static analysis composer check # both
License
Released under the MIT license.