How to quickly test websites with PHP’s built-in web server

0
41


Do you need to quickly start a web server to test a PHP application? The PHP interpreter has one built in! You can use this to quickly inspect your work without running Apache, NGINX, or a containerization solution.

Install WebBench to Benchmark Web S...
Install WebBench to Benchmark Web Server

PHP’s built-in server receives relatively little attention, but is quite powerful for development purposes. In this guide, we’ll show you how you can use it as an alternative to other microservers like Python’s SimpleHTTPServer or the http server npm package, neither of which can run PHP scripts.

Using the embedded server

The built-in server is a convenient mechanism to help you test PHP sites in environments that lack a full HTTP server. It is available in PHP 5.4 and all later versions. You can run it directly from your working directory without having to set up a virtual host first.

Before using the server, please note that it is designed for development only. The PHP documentation explicitly warns against implementing this server against production applications. It is not secure enough to be exposed on publicly accessible networks.

start the server

The server is started by passing the -S flag to the php executable:

$ php -S localhost:8080
[Fri Jun 10 16:00:00 2022] PHP 8.1.5 Development Server (http://localhost:8080) started

The argument given to the command specifies the listening address of the server. We have used the port 8080 in localhost in the example above. now you can visit http://localhost:8080 in your web browser to access the contents of your working directory. Any PHP script will be executed automatically when you request it.

You can serve a path that is outside of your working directory by setting the -t mark when you start the server:

$ php -S localhost:8080 -t /home/$USER/public_docs

The document root will now be /public_docs inside your home folder.

Keep your terminal window open while using the web server. Press Ctrl + C to finish the process once you are done testing your site. PHP will log each incoming request to your terminal window, including the URI and HTTP method. Any uncaught PHP errors will also appear in the logs.

Enabling remote access

listening in localhost it will not allow incoming connections from other devices on your network. You can allow remote access by linking to 0.0.0.0 instead:

$ php -S 0.0.0.0:8080

Remember that the server is not hardened for production use and should not be exposed publicly. Allow remote access only when absolutely necessary, such as when testing a particular feature on a mobile device. Make sure the port you are using is not open to the Internet.

Request booking match

PHP will search index.php Y index.html files in the active document root when the incoming request lacks a URI component. If none of these files exist, the server will continue moving up the directory tree, looking for an index in one of your document root’s parents. This means that you may inadvertently end up serving content that is outside of the directory you specified. A 404 Not Found status will be returned when the top of the tree is reached without an index file being found.

Requests that include a URI (such as /file) must exactly match a static file in the document root. Otherwise, a 404 will be returned. PHP automatically sets the Content-Type response header to the MIME type of the served file for the most popular file extensions.

Using a router script

Optionally, you can configure the web server to call a script on every request. This allows you to use the front controller of your application to perform advanced dynamic routing.

The router functionality is enabled by providing a PHP filename on the command line when you start the server:

$ php -S localhost:8080 router.php

PHP will now use router.php handle each incoming request. You can route users to the appropriate point in your application by inspecting the request URI:

if ($_SERVER["REQUEST_URI"] === "/dashboard") {
    require_once("dashboard.php");
}
else if ($_SERVER["REQUEST_URI"] === "/profile") {
    require_once("profile.php");
}
else {
    require_once("404.php");
}

The output produced by your router script will become the response sent to the client. An exception is if the script returns false: In this case, PHP will resort to returning the static file that matches the URI of the original request.

if (str_starts_with($_SERVER["REQUEST_URI"], "/api")) {
    // Route to the correct API endpoint
    // ... 
}
else {
    // Serve other routes statically
    return false;
}

Embedded server detection from your PHP code

Your PHP code can detect if the embedded web server is calling it by inspecting the name of the active interface. the php_sapi_name() function provides this value. will be set to cli-server when the script was invoked by the embedded server component.

if (php_sapi_name() === "cli-server") {
    enable_development_mode();
}

Handling multiple requests at the same time

The server runs in a single-process synchronous mode by default. Requests are handled individually and block each other from being executed until completed. This is one of the reasons why the server is not suitable for production use.

PHP 7.4 added support for handling multiple requests at the same time. It’s based on fork() availability and does not work on Windows. The server will fork a new worker to serve each incoming request when this mode is enabled. You can activate it by setting the PHP_CLI_SERVER_WORKERS environment variable to the number of workers you want:

$ PHP_CLI_SERVER_WORKERS=8 php -S localhost:8080

This functionality is still marked as experimental in PHP 8.1.

Summary

PHP has a built-in web server which is a convenient way to test your applications and quickly expose the contents of the local file system on your local network. Supports PHP script execution, general routing, and static files with the most common MIME types.

Although the server now supports an optional branch mode, it is not recommended to use it in production. It’s intended as a development aid and lacks the customization and security features you’ll need for your public deployments. Where it excels is as a lightweight, integrated alternative to mainstream development platforms like WAMP, XAMPP, and Docker containers.