Toko daring menyapa Anda dengan nama, mengingat keranjang belanja dari kemarin, dan mempertahankan tema gelap yang Anda pilih bulan lalu. Padahal protokol yang mendasari semuanya — HTTP — sama sekali tidak punya ingatan: setiap request diperlakukan seolah datang dari orang asing yang belum pernah bertemu. Jembatan antara kedua kenyataan itu adalah materi section ini. Sebelum menyentuh setcookie() atau session_start(), kita perlu memahami dulu masalah yang mereka selesaikan: apa itu state, mengapa HTTP tidak menyimpannya, dan mekanisme apa saja yang tersedia untuk menggendongnya.
HTTP Tidak Mengingat Siapa Pun #
Siklus dasar web adalah request–response: browser mengirim request, server membalas dengan response, lalu keduanya berpisah tanpa meninggalkan jejak. Saat script PHP selesai merespons, seluruh variabelnya — termasuk $_POST, $_GET, dan $_SESSION — ikut lenyap dari memori; request berikutnya menjalankan script yang sama dari nol, sebagaimana dibahas di chapter Request Lifecycle
. Server tidak punya konsep “pengguna yang sedang login” yang mengambang di udara; satu-satunya informasi yang dimiliki tentang request adalah apa yang dibawa request itu sendiri.
Sifat ini disebut stateless: tanpa keadaan. Bukan berarti HTTP tidak bisa mengirim data — justru setiap request boleh membawa data sebanyak apa pun di header, query string, dan body. Batasannya adalah kesinambungan: tidak ada mekanisme bawaan yang menghubungkan request hari ini dengan request kemarin. Simulasi berikut memperlihatkan satu-satunya jalan keluarnya — server menitipkan data pada response agar dikembalikan browser pada request berikutnya:
<?php
function tanganiRequest(array $request): array
{
// HTTP bersifat stateless: tidak ada ingatan tersisa dari request
// sebelumnya. Data satu-satunya adalah yang dibawa request ini sendiri.
$kunjungan = (int) ($request['cookies']['kunjungan'] ?? 0);
return [
'status' => 200,
'set-cookie' => 'kunjungan=' . ($kunjungan + 1),
'isi' => 'Ini kunjungan Anda yang ke-' . ($kunjungan + 1),
];
}
// Request pertama: browser belum menyimpan cookie apa pun
$requestPertama = ['cookies' => []];
// Request kedua: browser mengulang cookie yang sebelumnya diberikan server
$requestKedua = ['cookies' => ['kunjungan' => 1]];
echo json_encode(tanganiRequest($requestPertama)) . "\n";
echo json_encode(tanganiRequest($requestKedua)) . "\n";Output yang Dihasilkan:
{"status":200,"set-cookie":"kunjungan=1","isi":"Ini kunjungan Anda yang ke-1"}
{"status":200,"set-cookie":"kunjungan=2","isi":"Ini kunjungan Anda yang ke-2"}Pada request pertama, server tidak menemukan cookie apa pun sehingga menganggap ini kunjungan pertama, lalu menyertakan set-cookie: kunjungan=1 pada respons. Browser menyimpan cookie itu dan mengulanginya pada request kedua — barulah server bisa berkata “kunjungan Anda yang ke-2”. Kedua pemanggilan fungsi menjalankan kode yang persis sama tanpa memori bersama; kesinambungan tercipta murni karena data bolak-balik menggendong di setiap request. Inilah pola dasar seluruh teknik pengelolaan state di web.
Apa Itu State #
State adalah informasi tentang pengguna atau sesi kerja yang harus bertahan melewati satu request. Tiga kelompoknya paling sering muncul dalam aplikasi nyata:
| Jenis state | Contoh | Karakteristik |
|---|---|---|
| Pengenalan | “Halo, Budi”, halaman khusus login | Harus aman, tidak boleh bisa dipalsukan |
| Preferensi | Tema gelap, bahasa Indonesia | Tidak sensitif, boleh hilang tanpa bencana |
| Transaksi berjalan | Isi keranjang, langkah checkout ke-2 dari 4 | Berumur pendek, berubah di hampir tiap request |
Bayangkan masing-masing tanpa mekanisme state: setiap klik menjadikan Anda turunan — keranjang selalu kosong, tema kembali terang, tombol “Checkout” menanyakan Anda ini siapa. Aplikasi web modern nyaris mustahil dibangun di atas HTTP murni tanpa lapisan pengelolaan state di atasnya.
State yang Menumpang di Request #
Ada tiga cara klasik membuat state ikut berpindah bersama request, semuanya berada di sisi klien:
<?php
// State "menumpang" pada request itu sendiri dalam tiga bentuk berbeda
$requestHalamanProduk = [
'query' => ['halaman' => '2'], // GET /produk?halaman=2
'post' => ['kategori' => 'sepatu'], // hidden field pada form filter
'cookies' => ['tema' => 'gelap'], // header Cookie dari browser
];
printf("Halaman : %s\n", $requestHalamanProduk['query']['halaman']);
printf("Kategori : %s\n", $requestHalamanProduk['post']['kategori']);
printf("Tema : %s\n", $requestHalamanProduk['cookies']['tema']);Output yang Dihasilkan:
Halaman : 2
Kategori : sepatu
Tema : gelapKetiganya membawa potongan state yang sama-sama berharga namun berbeda kebiasaan kirimnya: query parameter hidup di URL sehingga bisa dibagikan dan di-bookmark, hidden field hanya berpindah saat form disubmit, dan cookie dikirim browser secara otomatis pada setiap request ke situs yang sama — termasuk request yang memuat sub-resource seperti gambar. Di PHP ketiganya sudah menyapa kita sebagai superglobal $_GET, $_POST, dan $_COOKIE sejak chapter PHP Superglobals
.
State di Sisi Server #
Satu mekanisme lagi bekerja dengan arah berbeda: session. Server menyimpan seluruh data state di penyimpanannya sendiri — file, Redis, database — dan hanya menitipkan satu cookie kecil berisi session ID pada browser. Saat request berikutnya tiba membawa ID itu, PHP memuat kembali data yang tersimpan, sehingga $_SESSION terasa seperti variabel yang tidak pernah mati. Data sensitif seperti status login dan isi keranjang sebaiknya tinggal di sini: tidak pernah terlihat di browser pengguna, tidak bisa diedit sembarangan, dan ukurannya tidak terikat batas cookie. Mekanisme lengkapnya menjadi agenda dua chapter setelah ini.
Memilih Mekanisme yang Tepat #
| Mekanisme | Disimpan di | Batas praktis | Terlihat pengguna | Cocok untuk |
|---|---|---|---|---|
| Cookie | Browser | ±4 KB per cookie | Ya, lewat devtools | Preferensi, session ID |
| Hidden field | Markup form | Sebesar halaman | Ya, lewat view source | Data antar langkah satu alur form |
| Query parameter | URL | ±2 KB | Ya, di address bar | Posisi halaman, filter pencarian |
| Session | Server | Memori/disk server | Tidak (hanya ID-nya) | Login, keranjang, data sensitif |
Kolom “terlihat pengguna” layak digarisbawahi: data di sisi klien selalu bisa dibaca dan dimodifikasi pemiliknya — prinsip batas kepercayaan dari chapter Form Security berlaku penuh di sini. Karena itu nilai penting seperti “sudah login sebagai admin” tidak boleh disimpan sebagai cookie mentah; simpan di session dan biarkan cookie hanya menggendong ID yang tak bermakna.
Desain Stateless sebagai Pilihan #
Menariknya, arsitektur modern justru sering memilih tetap stateless. API REST dan token JWT (JSON Web Token) memindahkan state ke dalam request itu sendiri: identitas dan klaim pengguna ditandatangani secara kriptografis lalu dikirim ulang pada setiap request, dan server cukup memverifikasi tanda tangan tanpa mencari-cari catatan di penyimpanannya. Server yang tidak menyimpan state mudah ditambah replikanya — load balancer bisa mengarahkan request ke mesin mana pun karena semua mesin setara. Konsekuensi dan pola desainnya dibandingkan tuntas di chapter penutup section ini, Stateless vs Stateful Applications .
Ringkasan #
HTTP memang stateless: setiap request adalah orang asing yang membawa seluruh konteksnya sendiri, dan script PHP selalu mulai dari nol. State — pengenalan, preferensi, transaksi berjalan — harus digendong bolak-balik: lewat cookie yang dikirim otomatis, hidden field yang menumpang form, query parameter yang hidup di URL, atau session ID yang menunjuk data di server. Pemahaman ini adalah peta jalan section ini. Kita mulai dari mekanisme paling dasar yang bisa Anda lihat langsung di browser: cookie, pada chapter berikutnya.