PHP and the Web

PHP was born on the web, and that's where it's most at home. In this lesson you'll start PHP's built-in development server, build pages that mix HTML and PHP, read values from the URL, and see how a request travels from the browser to your script and back.

The request–response cycle

  1. The browser sends an HTTP request: a method (usually GET or POST), a path such as /hello.php?name=Ana, and some headers.
  2. The web server sees that hello.php is a PHP file and asks PHP to run it.
  3. PHP runs the script. Everything the script outputs becomes the response body; the script can also set the status code and headers.
  4. The browser displays the HTML it received. The script has finished — the next request runs it again from the start.

The built-in web server

PHP includes a simple web server for development. In the folder that holds your .php files, run:

$
php -S localhost:8000

Now open http://localhost:8000/hello.php in your browser. The terminal logs each request; press Ctrl+C to stop the server. It handles one request at a time and isn't meant for production — real sites use nginx or Apache with PHP-FPM — but it's perfect for learning.

Mixing PHP and HTML

Anything outside <?php … ?> tags is sent to the browser unchanged, so a PHP file can be an HTML page with small islands of code. <?= … ?> is a short way to write <?php echo … ?>:

PHP hello.php
<?php
$title = "Welcome";
$visitors = 1280;
?>
<!DOCTYPE html>
<html lang="en">
<head><title><?= $title ?></title></head>
<body>
  <h1><?= $title ?>!</h1>
  <p>We've had <?= number_format($visitors) ?> visitors.</p>
  <p>2 + 2 = <?php echo 2 + 2; ?></p>
</body>
</html>
HTTP
GET /hello.php
Responses
> GET /hello.php
<!DOCTYPE html>
<html lang="en">
<head><title>Welcome</title></head>
<body>
  <h1>Welcome!</h1>
  <p>We've had 1,280 visitors.</p>
  <p>2 + 2 = 4</p>
</body>
</html>

Notice that a newline directly after a closing ?> is swallowed by PHP — which is why the output starts with <!DOCTYPE html> and not a blank line.

Reading the query string

Values after the ? in a URL are the query string. PHP puts them in the $_GET array automatically. The ?? operator supplies a default when a value is missing:

PHP greet.php
<?php
$name = $_GET['name'] ?? 'stranger';
$times = (int) ($_GET['times'] ?? 1);
?>
<?php for ($i = 0; $i < $times; $i++): ?>
<p>Hello, <?= htmlspecialchars($name) ?>!</p>
<?php endfor; ?>
HTTP
GET /greet.php
GET /greet.php?name=Ana&times=2
GET /greet.php?name=<b>Bold</b>
Responses
> GET /greet.php
<p>Hello, stranger!</p>
> GET /greet.php?name=Ana&times=2
<p>Hello, Ana!</p>
<p>Hello, Ana!</p>
> GET /greet.php?name=<b>Bold</b>
<p>Hello, &lt;b&gt;Bold&lt;/b&gt;!</p>

htmlspecialchars turns characters like < into safe HTML entities, so a visitor can't inject their own HTML or JavaScript into your page. Always escape user input when you output it into HTML — lesson 47 explains why in detail.

Information about the request

The $_SERVER array describes the current request and environment:

PHP info.php
<?php
header('Content-Type: text/plain');

echo "Method: {$_SERVER['REQUEST_METHOD']}\n";
echo "Path:   {$_SERVER['REQUEST_URI']}\n";
echo "Script: {$_SERVER['SCRIPT_NAME']}\n";
echo "Query:  {$_SERVER['QUERY_STRING']}\n";
HTTP
GET /info.php?page=2
Responses
> GET /info.php?page=2
< Content-Type: text/plain;charset=UTF-8
Method: GET
Path:   /info.php?page=2
Script: /info.php
Query:  page=2

Calling header() sets an HTTP response header — here, telling the browser the response is plain text rather than HTML. Headers must be sent before any other output (lesson 50).

Command line or web?

The same PHP language runs in both places, and your script can tell which one it's in with the PHP_SAPI constant ("cli" in a terminal, "cli-server" under the built-in server, "fpm-fcgi" under PHP-FPM). Most of this course's lessons run in the terminal because the output is easier to show and check. Part 9, "PHP on the Web", covers forms, sessions, cookies, uploads and routing in depth.

Where PHP runs in production

  • nginx or Apache + PHP-FPM — the standard setup on Linux servers.
  • Shared hosting — upload your files and they just work.
  • Platforms and frameworks — Laravel, Symfony and WordPress sites deployed to managed hosts, containers or serverless platforms.
  • Long-running application servers such as FrankenPHP or RoadRunner, which keep the application in memory between requests for extra speed.

Try it yourself

Save this as dice.php, start the server, and open it with different sides values in the URL.

Try it yourself · dice.php
Edit the code, copy it into dice.php, then start PHP's built-in web server with php -S localhost:8000 in that folder and open http://localhost:8000/dice.php (PHP 8.5). How to install PHP