How Nginx and PHP-FPM turn a web request into code
Let's see how an HTTP request gets from your web server into your PHP/Laravel code base.
The moving parts are:
- Nginx - receives web request, sends it to PHP-FPM via FastCGI
- PHP-FPM - Takes FastCGI request, spins up processes of PHP and runs your code
-
Laravel - Takes PHP super globals, along with
php://input
stream, and creates an HTTPRequest
class
Nginx
Nginx is configured for Laravel/PHP applications with the following config:
server {
server_name app.chipperci.com;
root /home/forge/app.chipperci.com/public;
index index.html index.htm index.php;
charset utf-8;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
error_page 404 /index.php;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
}
This is taken from Laravel Forge, with a bunch of items removed for brevity. What we see above are the parts we care about.
The first location / {}
uses try_files
to attempt to match the request URI to a static file or directory within the configured root
, which is /home/forge/app.chipperci.com/public
in our example. If it files a static file, it serves it! Otherwise, it runs index.php
.
If the file found ends in .php
(or we're using the fallback index.php
file), then we eventually end up in the location ~ \.php$ {}
block. This passes the request off to PHP-FPM via the FastCGI protocol.
It first splits the path at whatever *.php
file is in there. This lets PHP get the correct URI of the request - everything AFTER index.php
usually.
We also include fastcgi_params
which is the information that is populated in the $_SERVER
PHP super global.
Finally we pass the request off to PHP-FPM
, which in this case is listening via a unix socket file at /var/run/php/php8.2-fpm.sock
.
PHP-FPM
PHP-FPM is written in C, and is hard to parse (in other words, I have no idea what's going on in there). A lot of the logic to taking a request and spinning up PHP is in the fpm_request.c file. However the basics are that PHP-FPM manages processes and runs our PHP application through its "entrypoint", the index.php
file.
PHP-FPM populates the PHP super globals, any any streams needed such as php://input
(that will be the body of the HTTP request if there is one).
Our Code
Your framework likely abstracts the HTTP request into a class that represents the HTTP request itself. In Laravel, that's this class, which extends the underlying Symfony HTTP request here.
Laravel uses the method createFromGlobals()
, which creates an HTTP request instance based off of the global information (super globals) and gets the body of the HTTP request from php://input
.
Then Laravel can use that to match against registered routes, run controller code, and generally do all the magic it does for us!