Form adalah cara browser mengirim isian pengunjung ke server, dan PHP menerimanya sebagai array. Bayangin kertas pesanan di Warung Bu Tini. Pembeli mengisi menu, jumlah, dan catatan, lalu kertasnya diantar ke dapur. Kertas bisa diantar terbuka, isinya kebaca siapa saja yang lewat (itu GET, isinya ditempel di URL), atau di dalam amplop (itu POST, isinya di badan request). Di dapur, Bu Tini gak langsung percaya isinya: menunya dicek ada atau gak, jumlahnya masuk akal atau gak. PHP juga harus begitu.
🧪 Tebakan cepat: form pesanan punya checkbox "Pedas". Pembeli gak mencentangnya lalu menekan Pesan. Di PHP,
$_POST["pedas"]isinya apa:"",false, atau ada yang lain? Tebak dulu, jawabannya ada di bagian "Field yang gak terkirim".
Form mengirim, PHP menerima
<form method="post" action="pesan.php">
<select name="menu">
<option>Nasi Goreng</option><option>Mie Ayam</option><option>Es Teh</option>
</select>
<input name="jumlah" value="1">
<input name="catatan">
<label><input type="checkbox" name="pedas" value="ya"> Pedas</label>
<button>Pesan</button>
</form>
Pembeli memilih Nasi Goreng, mengetik jumlah 2, mencentang Pedas, lalu menekan Pesan. Browser mengirim request ini ke pesan.php:
POST /pesan.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded
menu=Nasi+Goreng&jumlah=2&catatan=&pedas=ya
Di pesan.php, isian itu sudah jadi array $_POST. print_r($_POST); menulis:
Array
(
[menu] => Nasi Goreng
[jumlah] => 2
[catatan] =>
[pedas] => ya
)
- Atribut
nametiap field jadi key array-nya, dan isian pembeli jadi value-nya. - Semua value berupa string. Jumlahnya
"2", bukan angka2. $_POSTdan$_GETdisebut superglobal: array bawaan PHP yang bisa dibaca dari mana saja di script.- Ganti
method="post"jadimethod="get", dan isian yang sama pindah ke URL:pesan.php?menu=Nasi+Goreng&jumlah=2&catatan=&pedas=ya. Isinya masuk$_GET, sementara$_POSTkosong.
| GET | POST | |
|---|---|---|
| Isian dikirim lewat | URL (query string, bagian setelah ?) |
badan request |
| Dibaca PHP dari | $_GET |
$_POST |
| Pas untuk | membaca: cari menu, halaman 2 | mengubah data: pesan, daftar, login |
| Kalau di-refresh | aman, cuma membaca lagi | browser bertanya mau kirim ulang atau gak |
Field yang gak terkirim: ?? dan isset
Checkbox yang gak dicentang gak dikirim sama sekali. Gak ada pedas= di request, jadi key pedas gak ada di $_POST. Membacanya langsung:
$pedas = $_POST["pedas"];
Warning: Undefined array key "pedas" in /var/www/warung/pesan.php on line 17
Isinya bukan "" atau false: key-nya gak ada, PHP memberi Warning dan $pedas jadi null (baris 17 adalah baris itu di pesan.php lengkap yang ada di Lab). Itu jawaban tebakannya. Input teks yang dikosongkan beda: dia tetap dikirim (catatan=), jadi $_POST["catatan"] ada dan isinya "".
Cara membaca yang aman:
if ($_SERVER["REQUEST_METHOD"] === "POST") {
$menu = $_POST["menu"] ?? "";
$catatan = $_POST["catatan"] ?? "";
$pedas = isset($_POST["pedas"]);
}
$_SERVER["REQUEST_METHOD"]berisi"GET"atau"POST". Halaman yang baru dibuka selalu GET, jadi form-nya baru diproses kalau memang dikirim dengan POST.??(null coalescing) memakai nilai di kanan kalau key di kiri gak ada ataunull. Gak ada Warning.isset($_POST["pedas"])menjawabtruekalau key-nya ada dan bukannull. Pas untuk checkbox.empty($_POST["catatan"])menjawabtruekalau key-nya gak ada atau isinya kosong ("","0",0,null). Hati-hati,empty("0")jugatrue.
Validasi: periksa semua field sebelum dipakai
Field wajib dicek satu per satu dengan perulangan, bukan ditulis berulang:
$_POST = ["nama" => "Budi", "email" => "", "pesan" => "Halo!"];
$valid = true;
foreach (["nama", "email", "pesan"] as $field) {
if (empty($_POST[$field])) {
echo "Error: $field wajib diisi\n";
$valid = false;
}
}
if ($valid) {
echo "Terima kasih, " . $_POST["nama"] . "! Pesan diterima.";
}
// Error: email wajib diisi
Untuk isi yang harus berupa angka atau email, pakai filter bawaan PHP:
$jumlah = filter_input(INPUT_POST, "jumlah", FILTER_VALIDATE_INT, [
"options" => ["min_range" => 1, "max_range" => 20],
]);
Isian jumlah |
Hasil |
|---|---|
2 |
int(2) |
3 (dengan spasi) |
int(3) |
dua, 2.5, 25, 0 |
false |
| field gak dikirim | null |
filter_inputmembaca langsung dari request, bukan dari array$_POST. Kalau kamu mengisi$_POSTsendiri (seperti di latihan), pakaifilter_var($_POST["jumlah"], FILTER_VALIDATE_INT, ...)dengan aturan yang sama.FILTER_VALIDATE_EMAILmemeriksa email:"[email protected]"lolos,"budi@mail"jadifalse.- Validasi di server wajib, walau form-nya sudah punya
requiredatautype="number". Request bisa dikirim tanpa lewat form-mu sama sekali.
Output: htmlspecialchars setiap kali menulis isian
Pembeli menulis catatan <b>pedas</b>. Kalau di-echo apa adanya, browser membacanya sebagai tag, dan catatan berisi <script> ikut dijalankan di browser orang lain. Itu XSS (cross-site scripting).
echo "<p>Catatan: " . htmlspecialchars($catatan) . "</p>";
// <p>Catatan: <b>pedas</b></p>
htmlspecialcharsmengubah<>&"'jadi<>&"'. Browser menampilkannya sebagai teks, gak membuka tag.- Di PHP 8.1 ke atas, flag bawaannya sudah termasuk
ENT_QUOTESdan charset-nya UTF-8, jadi untuk teks biasahtmlspecialchars($input)hasilnya sama denganhtmlspecialchars($input, ENT_QUOTES, "UTF-8")yang sering kamu temui di kode lama. - Escape dilakukan saat output, di tempat isiannya ditaruh. Detailnya ada di lesson XSS Prevention & Sanitization di track Security.
💡 POST/Redirect/GET
Setelah pesanan disimpan, kalau halaman POST langsung menulis "Pesanan masuk", tombol refresh mengirim POST yang sama lagi, dan pesanannya jadi dobel. Polanya: simpan, lalu suruh browser pindah dengan GET.
$id = simpanPesanan($menu, $jumlah, $catatan, $pedas);
header("Location: pesan.php?id=$id", true, 303);
exit;
header("Location: ...", true, 303)menjawab dengan status303 See Other. Browser langsung membukapesan.php?id=1dengan GET.exitmenghentikan script. Tanpa itu, kode di bawahnya tetap jalan.- Refresh sekarang cuma mengulang GET yang menampilkan pesanan #1. Gak ada pesanan baru.
Form POST yang mengubah data juga butuh CSRF token: nilai acak di input tersembunyi yang dicocokkan dengan yang disimpan di session. Tujuannya mencegah CSRF, yaitu situs lain diam-diam mengirim form ke warungmu atas nama pembeli yang sedang login. Caranya ada di lesson CSRF (Cross-Site Request Forgery) di track Security.
⚠️ Jebakan yang sering ketemu
- Membaca key yang mungkin gak ada.
$_POST["pedas"]dari checkbox yang gak dicentang memberiWarning: Undefined array key "pedas". Pakaiissetatau??. - Percaya isian karena ada validasi di HTML.
requireddantype="number"bisa dilewati. Periksa lagi di PHP denganempty,filter_var, ataufilter_input. echo $_POST["komentar"];tanpa escape. Itu celah XSS. Bungkus denganhtmlspecialchars().- Menulis satu
ifper field. Field wajib dicek denganforeachdi atas daftar nama field, jadi field baru cukup ditambahkan ke daftarnya.
TL;DR: Form mengirim isiannya ke PHP: method="get" lewat URL ke $_GET, method="post" lewat badan request ke $_POST. Key-nya dari atribut name, value-nya selalu string. Checkbox yang gak dicentang gak dikirim, jadi membacanya langsung memberi Warning: Undefined array key; baca dengan isset() atau ??, dan cek $_SERVER["REQUEST_METHOD"] === "POST" dulu. Validasi semua field di server (foreach + empty, filter_input/filter_var dengan FILTER_VALIDATE_INT), lalu tulis isian ke halaman lewat htmlspecialchars() supaya gak jadi XSS. Setelah POST berhasil, redirect dengan header("Location: ...", true, 303); exit; supaya refresh gak mengirim ulang, dan form POST yang mengubah data butuh CSRF token.