Menjembatani PHP dengan pengguna web: memproses $_GET dan $_POST dengan validasi yang benar, mengelola file upload secara aman, lalu menyusun response lengkap mulai dari status code, redirect, JSON, hingga cookie dan session dengan secure flags yang mencegah serangan.

PHP lahir dari pemrosesan form — dan hingga hari ini, form handling adalah urat nadi aplikasi web: login, pendaftaran, checkout, pencarian, semuanya berawal dari data yang dikirim pengguna melalui HTTP. Episode ini membahas cara menerima, memvalidasi, dan merespons input itu dengan benar.
Mengapa penting? Input dari pengguna adalah sumber hampir semua serangan web (SQL injection, XSS, CSRF). Cara kalian memvalidasi dan meng-escape input menentukan apakah aplikasi kalian aman. Dan sisi respons — status code, redirect, cookie, session — menentukan pengalaman pengguna dan ketepatan protokol HTTP.
$_GET dan $_POSTPHP mengisi superglobal $_GET, $_POST, $_FILES, $_COOKIE, $_SESSION, dan $_SERVER secara otomatis per request:
<?php
declare(strict_types=1);
// ?q=php&page=2 → /search.php?q=php&page=2
$q = $_GET["q"] ?? "";
$page = max(1, (int) ($_GET["page"] ?? 1));
// data dari <form method="POST">
$nama = $_POST["nama"] ?? "";
$email = $_POST["email"] ?? "";Aturan emas membaca input:
?? untuk nilai default — jangan akses $_GET["x"] langsung (warning + null).(int) untuk angka.Validasi di sisi server — validasi client (HTML) hanya kenyamanan, bisa dilewati siapa pun:
$errors = [];
$nama = trim((string) ($_POST["nama"] ?? ""));
$email = strtolower(trim((string) ($_POST["email"] ?? "")));
$usia = (int) ($_POST["usia"] ?? 0);
if ($nama === "") {
$errors[] = "Nama wajib diisi.";
}
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors[] = "Email tidak valid.";
}
if ($usia < 17 || $usia > 120) {
$errors[] = "Usia di luar rentang wajar.";
}
if ($errors !== []) {
http_response_code(422);
foreach ($errors as $e) {
echo "<li>" . htmlspecialchars($e) . "</li>";
}
exit;
}Catatan kunci: kita memvalidasi dan meng-escape — htmlspecialchars() di output mencegah XSS (dibahas tuntas episode 17). Di framework (episode 13) validasi ini di-handle validator bawaan.
Upload file butuh form dengan enctype="multipart/form-data":
<form method="post" action="upload.php" enctype="multipart/form-data">
<input type="file" name="foto" accept="image/*" required>
<button type="submit">Unggah</button>
</form>Handler yang aman:
$foto = $_FILES["foto"] ?? null;
if (!$foto || $foto["error"] !== UPLOAD_ERR_OK) {
http_response_code(400);
exit("Upload gagal.");
}
$allowed = ["image/jpeg", "image/png", "image/webp"];
$realMime = (new finfo(FILEINFO_MIME_TYPE))->file($foto["tmp_name"]);
if (!in_array($realMime, $allowed, true)) {
http_response_code(400);
exit("Tipe file tidak diizinkan.");
}
if ($foto["size"] > 2 * 1024 * 1024) {
http_response_code(413);
exit("File terlalu besar (maks 2MB).");
}
$namaBaru = bin2hex(random_bytes(16)) . "." . pathinfo($foto["name"], PATHINFO_EXTENSION);
move_uploaded_file($foto["tmp_name"], __DIR__ . "/uploads/" . $namaBaru);
echo "File tersimpan: $namaBaru";Poin penting: cek MIME asli (bukan ekstensi saja), batasi ukuran, dan ganti nama file dengan nilai acak — praktik ini mencegah upload file berbahaya dan path traversal (episode 17).
http_response_code(404);
echo "Halaman tidak ditemukan";
// Redirect 302 / permanent 301
header("Location: /dashboard", true, 302);
exit;header() harus dipanggil sebelum output apa pun dikirim.
Untuk API (episode 13):
header("Content-Type: application/json; charset=utf-8");
http_response_code(201);
echo json_encode(
["status" => "ok", "data" => ["id" => 42, "nama" => "Devvnull"]],
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
);JSON_UNESCAPED_UNICODE menjaga karakter UTF-8 (misal "Sate") agar tidak jadi \uXXXX.
Session menyimpan state di server (yang di client hanya ID acak):
session_start();
$_SESSION["user_id"] = 42;
$_SESSION["role"] = "admin";Cookie menyimpan data di browser pengguna — pasang secure flags:
setcookie(
"preferensi_theme",
"dark",
[
"expires" => time() + 3600 * 24 * 30,
"path" => "/",
"secure" => true, // hanya via HTTPS
"httponly" => true, // tidak bisa dibaca JavaScript
"samesite" => "Lax", // perlindungan CSRF dasar
]
);Tiga flag ini wajib untuk cookie berisi data sensitif:
| Flag | Fungsi |
|---|---|
secure | Hanya dikirim lewat HTTPS |
httponly | JavaScript tidak bisa membacanya (tameng XSS) |
samesite=Lax/Strict | Membatasi cookie dikirim pada request lintas situs (tameng CSRF) |
Warning
Jangan pernah menyimpan password atau data sensitif di cookie — cookie bisa dicuri via XSS dan dibaca pengguna. Gunakan session (ID acak) untuk data sensitif, dan pastikan session di-hardening (regenerate ID setelah login, batasi lifetime). Detailnya di episode 14 dan 17.
header() setelah output — error "headers already sent"; pastikan tidak ada whitespace/BOM sebelum <?php.$_GET/$_POST diakses tanpa ?? — warning + null; gunakan default.httponly/secure — mudah dicuri; pasang ketiganya.session_regenerate_id() setelah login.Inti yang harus dibawa pulang:
$_GET/$_POST + ??, lalu validasi di server dan konversi eksplisit.http_response_code, header() sebelum output, JSON dengan json_encode.secure, httponly, samesite) dan session yang di-regenerate.Di episode 13 selanjutnya kita naik level ke produksi: REST API & Framework (Laravel/Slim) — routing, controller, validation, dan response pattern, lalu perbandingan Laravel, Symfony, Slim, dan CodeIgniter untuk memilih alat yang tepat. Aplikasi kalian mulai berbentuk seperti produk sungguhan.