Chapter HTML Forms dan PHP
memperlihatkan bagaimana form mengumpulkan isi field menjadi kiriman yang bisa dibaca PHP. Namun ada satu keputusan desain yang menentukan nasib kiriman tersebut: method pengiriman. Form HTML hanya mengenal dua pilihan — GET dan POST — dan keduanya bukan sekadar “dua cara yang sama”. Pilihan method menentukan lokasi data berada, apakah hasil pencarian bisa dibagikan sebagai tautan, apakah kata sandi sempat tercatat di riwayat browser, sampai bagaimana browser bereaksi ketika pengguna menekan tombol refresh. Pada chapter ini kita bedah kedua method dari sisi lokasi data, semantik request, dan perilaku browser, lalu menutupnya dengan panduan praktis memilih method untuk setiap situasi.
Lokasi Data: Query String atau Request Body #
Saat tombol submit ditekan, browser mengumpulkan setiap field menjadi pasangan name=nilai. Method-lah yang menentukan cara paket data tersebut dikirim ke server. Dengan GET, pasangan data ditempelkan ke URL setelah tanda tanya (?) — bagian yang disebut query string. Dengan POST, data dikirim di body request sehingga tidak pernah muncul di address bar.
<form action="/cari.php" method="get">
<label for="kata">Kata kunci</label>
<input type="text" id="kata" name="kata">
<button type="submit">Cari</button>
</form><form action="/daftar.php" method="post">
<label for="nama">Nama lengkap</label>
<input type="text" id="nama" name="nama">
<button type="submit">Daftar</button>
</form>Form pertama menghasilkan URL seperti /cari.php?kata=kopi+gayo yang bisa dibaca utuh di address bar, sedangkan form kedua tetap menuju /daftar.php dengan data tersembunyi di body. Perlu dicatat: bila atribut method dihilangkan, browser memakai GET sebagai bawaan. Tabel berikut merangkum perbedaan yang akan kita bahas satu per satu:
| Aspek | GET | POST |
|---|---|---|
| Lokasi data | query string pada URL | body request |
| Terlihat di address bar | ya, lengkap | tidak |
| Batas ukuran praktis | sekitar 2.000 karakter | dibatasi konfigurasi server, jauh lebih longgar |
| Bookmark dan tautan | bisa — data ikut tersimpan di URL | tidak — data hilang saat URL disimpan |
| Cache | boleh di-cache browser dan proxy | tidak pernah di-cache |
| Jejak di riwayat dan log | data tercatat sebagai URL di riwayat browser dan log server | URL tetap bersih, data tidak tercatat sebagai URL |
| Wajar untuk | mencari, memfilter, memilih halaman | mendaftar, login, memesan, mengubah data |
Semantik: Membaca atau Mengubah #
Dua properti method sudah kita kenal di Chapter HTTP Methods
: GET bersifat safe (tidak mengubah keadaan server) dan idempotent (mengulang request memberi efek yang sama), sedangkan POST tidak keduanya. Konsekuensinya nyata di lapangan. Browser hanya berani melakukan prefetch terhadap request GET karena method tersebut dijamin aman, dan crawler mesin pencari menelusuri semua tautan GET yang ditemukannya.
Karena itu, tautan yang mengubah data — misalnya href="/hapus-pesanan.php?id=7" — adalah kecelakaan yang menunggu waktu: crawler atau fitur prefetch bisa mengeksekusi penghapusan tanpa ada niat dari pengunjung. Semua aksi yang mengubah keadaan server (menyimpan, menghapus, login) harus melalui POST, karena tidak ada mekanisme otomatis yang akan mengirimkannya tanpa konfirmasi pengguna.
Membedah Query String GET #
Di web nyata, PHP sudah memilah query string ke dalam $_GET secara otomatis. Untuk memahami format yang sedang diurai, kita bedah sendiri sebuah URL lengkap menggunakan parse_url() dan parse_str():
<?php
$url = 'https://www.contoh.com/cari?kata=kopi+gayo&halaman=2';
$bagian = parse_url($url);
print_r($bagian);
parse_str($bagian['query'], $params);
print_r($params);Output yang Dihasilkan:
Array
(
[scheme] => https
[host] => www.contoh.com
[path] => /cari
[query] => kata=kopi+gayo&halaman=2
)
Array
(
[kata] => kopi gayo
[halaman] => 2
)Mari kita bedah kedua langkah di atas:
parse_url($url): memecah URL menjadi komponen —scheme,host,path, danquery— tanpa mengurai isi query string itu sendiri.parse_str($bagian['query'], $params): mengurai query string menjadi associative array$params; tanda+yang menggantikan spasi dikembalikan menjadi spasi (kopi+gayomenjadikopi gayo).- Perhatikan bahwa semua nilai berupa
string—'2', bukan integer2— persis seperti isi$_GETdi web nyata.
Arah sebaliknya juga tersedia: http_build_query() membangun query string yang valid dari array, lengkap dengan pengodean karakter.
<?php
$kriteria = [
'kategori' => 'buku',
'kata' => 'kopi gayo',
'halaman' => 3,
];
$url = 'https://www.contoh.com/produk?' . http_build_query($kriteria);
echo $url . "\n";Output yang Dihasilkan:
https://www.contoh.com/produk?kategori=buku&kata=kopi+gayo&halaman=3Spasi pada nilai kopi gayo dikodekan menjadi +, dan tiap pasangan digabung dengan &. Fungsi ini sangat berguna saat membangun tautan paginasi atau menyimpan state filter ke dalam URL. Untuk membuktikan bahwa PHP memang mengisi $_GET dari query string, kami menguji handler berikut lewat built-in web server:
<?php
// cari.php — jalankan lewat built-in server: php -S 127.0.0.1:8099
header('Content-Type: text/plain; charset=utf-8');
$kata = trim($_GET['kata'] ?? '');
$halaman = (int) ($_GET['halaman'] ?? 1);
echo "Mencari: '$kata' (halaman $halaman)";curl "http://127.0.0.1:8099/cari.php?kata=kopi+gayo&halaman=2"
curl "http://127.0.0.1:8099/cari.php"Permintaan pertama dijawab Mencari: 'kopi gayo' (halaman 2) — PHP mengisi $_GET['kata'] dan $_GET['halaman'] persis dari query string, dan nilai '2' di-cast menjadi integer 2. Permintaan kedua tanpa query string dijawab Mencari: '' (halaman 1): array $_GET kosong, operator ?? memberi nilai cadangan, sehingga tidak ada peringatan yang muncul.
Batas Ukuran dan Data Sensitif #
Spesifikasi HTTP tidak menetapkan batas panjang URL, tetapi kombinasi browser, server, dan proxy di lapangan menjadikan sekitar 2.000 karakter patokan yang aman untuk GET. Form dengan banyak field atau teks panjang — misalnya kolom pesan — sebaiknya dikirim lewat POST. Batas POST diatur oleh directive post_max_size di sisi server (bawaannya 8M pada kebanyakan instalasi), jauh di atas kebutuhan form biasa.
Bookmark, Cache, dan Bahaya Refresh #
Karena data GET hidup di URL, hasil pencarian otomatis menjadi tautan yang bisa dibagikan lewat email atau grup chat, dan disimpan sebagai bookmark yang selalu membuka hasil yang sama. Browser dan proxy juga berhak menyimpan cache halaman GET sehingga halaman yang sama dibuka lebih cepat tanpa membebani server.
POST memberi perilaku yang berbeda. Menekan tombol refresh setelah submit POST memunculkan dialog konfirmasi seperti “Kirim ulang form?” — browser tahu POST tidak idempoten dan menolak mengulangnya secara diam-diam. Sayangnya, bila pengguna menyetujui dialog tersebut, pesanan yang sama bisa terkirim dua kali. Solusi yang rapi untuk masalah ini adalah pola Post/Redirect/Get, yang kita bahas tuntas pada Chapter Post/Redirect/Get .
Menangani GET dan POST dalam Satu Skrip #
Pola yang paling umum di aplikasi PHP: satu skrip melayani dua peran — request GET menampilkan form kosong, request POST memproses kiriman. Berikut versi yang bisa diuji dari CLI dengan parameter tiruan:
<?php
function tanganiHalamanPendaftaran(string $method, array $post): string
{
if ($method !== 'POST') {
return 'Menampilkan form pendaftaran';
}
$nama = trim($post['nama'] ?? '');
if ($nama === '') {
return 'TOLAK: nama wajib diisi';
}
return "TERIMA: pendaftar $nama tersimpan";
}
echo tanganiHalamanPendaftaran('GET', []), "\n";
echo tanganiHalamanPendaftaran('POST', ['nama' => 'Budi']), "\n";
echo tanganiHalamanPendaftaran('POST', ['nama' => ' ']), "\n";Output yang Dihasilkan:
Menampilkan form pendaftaran
TERIMA: pendaftar Budi tersimpan
TOLAK: nama wajib diisiMari kita telaah handler di atas:
- Parameter
$method: menggantikan pembacaan$_SERVER['REQUEST_METHOD']supaya fungsi bisa diuji dari CLI tanpa server — pola yang dipakai di seluruh section ini. trim($post['nama'] ?? ''): merapikan spasi dan memberi nilai cadangan sekaligus; kiriman' '(hanya spasi) diperlakukan sama seperti kosong.- Pemeriksaan
$nama === '': contoh validasi paling sederhana di sisi server; versi lengkapnya dibangun pada Chapter Validasi Server-Side .
Di web nyata, handler yang sama membaca superglobal langsung. Kami mengujinya dengan built-in server dan curl:
<?php
// daftar.php — jalankan lewat built-in server: php -S 127.0.0.1:8099
header('Content-Type: text/plain; charset=utf-8');
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$nama = trim($_POST['nama'] ?? '');
if ($nama === '') {
http_response_code(422);
echo 'TOLAK: nama wajib diisi';
exit;
}
echo "TERIMA: pendaftar $nama tersimpan";
exit;
}
echo 'Menampilkan form pendaftaran';curl -X POST -d "nama=" http://127.0.0.1:8099/daftar.php
curl -X POST -d "nama=Budi" http://127.0.0.1:8099/daftar.phpKiriman nama= (kosong) dijawab TOLAK: nama wajib diisi dengan status HTTP 422, sedangkan nama=Budi dijawab TERIMA: pendaftar Budi tersimpan. Opsi -d pada curl mengirim body form seolah-olah berasal dari browser — pengingat bahwa server tidak pernah tahu, dan tidak peduli, apakah kiriman datang dari form HTML yang kita tulis atau dari perintah yang diketik langsung.
Panduan Memilih Method #
Keputusan method bisa dipersingkat menjadi dua daftar berikut:
- Pilih GET bila request hanya membaca data: pencarian, filter, paginasi, halaman detail lewat
?id=; hasilnya layak dibagikan sebagai tautan; datanya pendek dan tidak sensitif. - Pilih POST bila request mengubah keadaan server: pendaftaran, login, pesanan, penghapusan, komentar; bila ada data sensitif seperti kata sandi; bila ada unggahan berkas (yang selalu memakai
multipart/form-data); atau bila datanya besar.
Ada satu pertanyaan cepat yang hampir selalu menjawab: “bolehkah tautan ini diklik otomatis oleh crawler atau prefetch browser tanpa efek samping?” Bila jawabannya tidak, request tersebut bukan urusan GET.
Sekilas ke Arah REST #
GET dan POST adalah fondasi yang akan dipakai sepanjang karier Anda membangun web. Begitu beranjak ke API, keduanya ditemani method yang lebih ekspresif — PUT, PATCH, DELETE — yang memetakan operasi data secara presisi, dengan bantuan teknik method spoofing untuk form HTML. Semantik safe, idempotent, dan lokasi data yang dilatih di chapter ini langsung terpakai di sana; pembahasan lengkapnya menanti di Section REST API Development
.
Ringkasan #
GET menempatkan data di query string: terlihat di address bar, berbatas pendek, bisa di-bookmark dan di-cache, serta secara semantik aman untuk operasi baca. POST menempatkan data di body: tersembunyi, longgar ukurannya, tidak pernah di-cache, dan menjadi satu-satunya pilihan yang benar untuk perubahan state. Pemahaman ini menjadi dasar bagi seluruh chapter berikutnya — karena setelah method terpilih, langkah berikutnya adalah membaca kiriman form itu sendiri di sisi PHP, topik Chapter Membaca Form Input .