This chapter explains the Hypertext Transfer Protocol (HTTP) at a level suitable for undergraduate web programming students who are using PHP. It mixes conceptual material with hands-on PHP examples and practical debugging tips.
Coursera HTTP: A video lecture on HTTP from the associated Coursera course.
HTTP is an application-level protocol for exchanging messages between clients (usually browsers or API clients) and servers (web servers + application code). It is request → response: a client sends a request and the server returns a response.
Key ideas:
https:// it is HTTP over TLS.GET /index.php?q=php-http HTTP/1.1
Host: example.com
User-Agent: curl/8.0
Accept: text/html
Cookie: session=abcd1234
HTTP/1.1 200 OK
Date: Tue, 16 Dec 2025 12:00:00 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 142
<!doctype html>
<html><body><h1>Hello</h1></body></html>
Sections:
METHOD PATH PROTOCOL) or status line (PROTOCOL STATUS REASON).Idempotent: same request repeated yields same result (e.g., PUT, GET).
2xx: success
200 OK, 201 Created, 204 No Content3xx: redirection
301 Moved Permanently, 302 Found, 304 Not Modified4xx: client error
400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 422 Unprocessable Entity5xx: server error
500 Internal Server Error, 502 Bad Gateway, 503 Service UnavailableUse the correct code to make APIs predictable for clients.
Host — required for virtual hosting.Content-Type — MIME type of the body, e.g. application/json, text/html, multipart/form-data.Accept — what the client can accept.Authorization — credentials, e.g. Bearer <token>.Cookie / Set-Cookie — session cookies.Cache-Control, ETag, Last-Modified — caching.Location — for redirects.Access-Control-Allow-Origin, Access-Control-Allow-Methods — CORS control.http, https).www.example.com).:80 for HTTP, :443 for HTTPS).Here is a diagram illustrating the components of a URL:
+--------+ +------------------+ +------+ +------------------+
| Scheme | -> | Host | -> | Port | -> | Path |
+--------+ +------------------+ +------+ +------------------+
| | | |
http:// www.example.com :80 /index.php?q=test
In web programming, a port is a number that identifies which service or application on a computer should receive network traffic.
Think of a computer as a large building with many doors:
So when data arrives over the internet, the port tells the computer which program should handle it.
A port is a logical endpoint used by the operating system to route incoming and outgoing network data to the correct application.
A single machine can run many network services at the same time:
Ports allow all of these to coexist on one IP address without confusion.
| Port | Purpose |
|---|---|
| 80 | HTTP (standard web pages) |
| 443 | HTTPS (secure web pages) |
| 3000 | Common for development servers (Node.js) |
| 3306 | MySQL database |
| 5432 | PostgreSQL database |
Ports appear after the hostname, separated by a colon:
http://localhost:3000
https://example.com:443
localhost → the computer3000 → which service on that computerIf no port is specified, the browser assumes the default:
HTTPS → port 443
A port tells your computer which program should receive the network request, just like a door number tells you which room to enter.
curl / httpiephp -S localhost:8000 — simple PHP web server for developmentExamples:
# simple GET
curl -i http://localhost:8000/index.php?q=test
# POST JSON
curl -i -X POST http://localhost:8000/api.php \
-H "Content-Type: application/json" \
-d '{"name":"Alice"}'
# from your project directory
php -S localhost:8000
// GET parameters
$q = $_GET['q'] ?? null;
// POST form-encoded
$name = $_POST['name'] ?? null;
// Raw body (for JSON APIs)
$raw = file_get_contents('php://input');
$data = json_decode($raw, true);
// set a status code
http_response_code(201);
// set custom header
header('Content-Type: application/json');
// send JSON response
echo json_encode(['id' => 123, 'name' => 'Alice']);
header('Location: /login.php');
http_response_code(302);
exit;
setcookie('session', $sessionId, [
'expires' => time() + 3600,
'path' => '/',
'httponly' => true,
'secure' => true, // only over HTTPS
'samesite' => 'Lax',
]);
api.php
<?php
// simple router
$method = $_SERVER['REQUEST_METHOD'];
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
if ($path === '/api/notes' && $method === 'GET') {
header('Content-Type: application/json');
echo json_encode(['notes' => [['id'=>1,'text'=>'Intro to HTTP']]]);
exit;
}
if ($path === '/api/notes' && $method === 'POST') {
$raw = file_get_contents('php://input');
$body = json_decode($raw, true);
if (!isset($body['text'])) {
http_response_code(400);
echo json_encode(['error' => 'text required']);
exit;
}
// pretend to create note...
http_response_code(201);
header('Content-Type: application/json');
echo json_encode(['id' => 2, 'text' => $body['text']]);
exit;
}
http_response_code(404);
echo "Not found";
Test with curl:
curl -i http://localhost:8000/api/notes
curl -i -X POST http://localhost:8000/api/notes \
-H "Content-Type: application/json" \
-d '{"text":"Learn HTTP"}'
Clients declare Accept; servers choose response format. For simple APIs, support JSON (application/json) only and return 415 Unsupported Media Type if Content-Type is wrong.
Example content-type check:
if ($_SERVER['CONTENT_TYPE'] !== 'application/json') {
http_response_code(415);
echo json_encode(['error' => 'Expected application/json']);
exit;
}
Cache-Control (no-cache, max-age, public/private)ETag and If-None-Match — server can return 304 Not Modified when content unchanged.Example:
header('Cache-Control: public, max-age=3600');
Strict-Transport-Security).Secure, HttpOnly, and SameSite attributes.header('Access-Control-Allow-Origin: https://your-frontend.example');
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
Handle OPTIONS preflight by returning allowed headers and methods with 204 No Content.
Authorization: Bearer <token>, CSRF is less relevant since tokens aren’t sent automatically by browsers.HTML form:
<form method="post" enctype="multipart/form-data" action="/upload.php">
<input type="file" name="avatar">
<button>Upload</button>
</form>
PHP handling:
if (!empty($_FILES['avatar']) && $_FILES['avatar']['error'] === UPLOAD_ERR_OK) {
$tmp = $_FILES['avatar']['tmp_name'];
$name = basename($_FILES['avatar']['name']);
$dest = __DIR__ . '/uploads/' . $name;
move_uploaded_file($tmp, $dest);
echo "Saved";
} else {
echo "Upload failed";
}
Security: validate MIME type and file extensions, store outside web root or with randomized names, limit size.
200 on errors (use appropriate 4xx/5xx).$_POST for JSON payloads (need php://input).Content-Type on responses.Access-Control-Allow-Origin: * for authenticated endpoints.Q: Why should form submissions that change server state use POST instead of GET? A: GET is intended for safe retrieval and can be cached/bookmarked/appears in logs/URL. POST signals non-idempotent change and hides payload from URL.
Task: Write a PHP endpoint /api/echo that accepts JSON {"message":"..."} and returns {"echo":"..."} with status 200.
Suggested answer (skeleton):
$raw = file_get_contents('php://input');
$data = json_decode($raw, true);
if (!isset($data['message'])) {
http_response_code(400);
echo json_encode(['error'=>'message required']);
exit;
}
header('Content-Type: application/json');
echo json_encode(['echo' => $data['message']]);
Q: What response should the server send to an OPTIONS preflight request?
A: Return 204 No Content (or 200) with Access-Control-Allow-Origin, Access-Control-Allow-Methods, and Access-Control-Allow-Headers including whatever the client requested.
header(), setcookie(), session_*, file upload docs.curl manual — useful for scripting tests.