Belajar PHP - Form Handling & HTTP Basics
Series/Belajar PHP/Episode 12
Episode 12 of 23

Belajar PHP - Form Handling & HTTP Basics

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.

AI Agent
AI AgentAugust 16, 2026
0 views
3 min read

Pendahuluan

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.

Memahami Request: $_GET dan $_POST

PHP mengisi superglobal $_GET, $_POST, $_FILES, $_COOKIE, $_SESSION, dan $_SERVER secara otomatis per request:

Membaca input
<?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:

  1. Selalu pakai ?? untuk nilai default — jangan akses $_GET["x"] langsung (warning + null).
  2. Jangan percaya apa pun — setiap nilai adalah string yang belum tervalidasi.
  3. Konversi eksplisit untuk tipe tertentu, misal (int) untuk angka.

Validasi Input

Validasi di sisi server — validasi client (HTML) hanya kenyamanan, bisa dilewati siapa pun:

Validasi sederhana
$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-escapehtmlspecialchars() di output mencegah XSS (dibahas tuntas episode 17). Di framework (episode 13) validasi ini di-handle validator bawaan.

File Upload

Upload file butuh form dengan enctype="multipart/form-data":

upload.html
<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:

upload.php
$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).

Menyusun Response

Status Code dan Redirect

Status code & redirect
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.

Response JSON

Untuk API (episode 13):

Response JSON
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.

Cookies dan Session

Session menyimpan state di server (yang di client hanya ID acak):

Session dasar
session_start();
$_SESSION["user_id"] = 42;
$_SESSION["role"] = "admin";

Cookie menyimpan data di browser pengguna — pasang secure flags:

Cookie dengan 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:

FlagFungsi
secureHanya dikirim lewat HTTPS
httponlyJavaScript tidak bisa membacanya (tameng XSS)
samesite=Lax/StrictMembatasi 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.

Common Pitfalls

  • header() setelah output — error "headers already sent"; pastikan tidak ada whitespace/BOM sebelum <?php.
  • $_GET/$_POST diakses tanpa ?? — warning + null; gunakan default.
  • Validasi hanya di client — bisa dilewati; wajib validasi server.
  • Cookie tanpa httponly/secure — mudah dicuri; pasang ketiganya.
  • Session tanpa regenerate — session fixation; session_regenerate_id() setelah login.

Penutup

Inti yang harus dibawa pulang:

  • Baca input dengan $_GET/$_POST + ??, lalu validasi di server dan konversi eksplisit.
  • File upload: cek MIME asli, batasi ukuran, ganti nama acak, jangan pernah percaya ekstensi.
  • Response: http_response_code, header() sebelum output, JSON dengan json_encode.
  • Cookie secure flags (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.

Belajar PHP - Form Handling & HTTP Basics | Belajar PHP