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
- The browser sends an HTTP request: a method (usually
GETorPOST), a path such as/hello.php?name=Ana, and some headers. - The web server sees that
hello.phpis a PHP file and asks PHP to run it. - PHP runs the script. Everything the script outputs becomes the response body; the script can also set the status code and headers.
- 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 $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>
GET /hello.php
> 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 $name = $_GET['name'] ?? 'stranger'; $times = (int) ($_GET['times'] ?? 1); ?> <?php for ($i = 0; $i < $times; $i++): ?> <p>Hello, <?= htmlspecialchars($name) ?>!</p> <?php endfor; ?>
GET /greet.php GET /greet.php?name=Ana×=2 GET /greet.php?name=<b>Bold</b>
> GET /greet.php <p>Hello, stranger!</p> > GET /greet.php?name=Ana×=2 <p>Hello, Ana!</p> <p>Hello, Ana!</p> > GET /greet.php?name=<b>Bold</b> <p>Hello, <b>Bold</b>!</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 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";
GET /info.php?page=2
> 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.