Kita sudah berkenalan dengan kedelapan superglobals dari sisi bahasa pada Chapter Superglobals
: array istimewa yang terisi otomatis dan terlihat di semua scope. Kini waktunya melihatnya dari sisi web — bagaimana isi tiap array terbentuk dari request HTTP yang sesungguhnya, bagaimana $_REQUEST menggabungkan tiga sumber sekaligus, dan mengapa seluruhnya berada di luar batas kepercayaan aplikasi. Chapter ini juga memperkenalkan extension filter sebagai alat baca yang lebih disiplin, membedah struktur $_FILES untuk unggahan berkas, lalu menutup dengan kisah register_globals — fitur lama yang menjadi pelajaran abadi tentang kepercayaan data.
Isi Superglobals pada Request Web #
Tabel pada chapter pengantar sudah memetakan delapan superglobal; di sini kita fokus pada apa yang masing-masing berisi ketika request web sungguhan tiba di skrip PHP:
| Superglobal | Sumber pada request web | Contoh isi |
|---|---|---|
$_GET | Query string pada URL | ?halaman=2 menjadi ['halaman' => '2'] |
$_POST | Body request form application/x-www-form-urlencoded atau multipart/form-data | field form seperti email |
$_COOKIE | Header Cookie yang dikirim browser | pengenal session |
$_FILES | Bagian berkas dari multipart/form-data | name, tmp_name, size, error |
$_SERVER | Data yang disiapkan server: method, URI, header HTTP_* | REQUEST_METHOD, HTTP_HOST |
$_REQUEST | Gabungan $_GET + $_POST + $_COOKIE | gabungan ketiganya |
$_ENV | Variabel environment proses PHP | konfigurasi deployment |
Perhatikan bahwa $_SESSION tidak hadir pada tabel di atas — array tersebut hanya tersedia setelah session_start() dan mekanismya lengkap dengan tantangan keamanannya sendiri, sehingga dibahas pada Section HTTP State: Sessions dan Cookies
. Media type application/x-www-form-urlencoded dan multipart/form-data yang muncul pada tabel sudah kita bedah dari sisi formatnya pada Chapter Content Types
.
Superglobal Terlihat dari Dalam Fungsi #
Kata “super” pada superglobal berarti satu hal praktis: array tersebut terdefinisi di semua scope tanpa keyword global — berbeda dari variabel biasa yang tersembunyi di dalam fungsi, seperti dibahas pada Chapter Variable Scope
. Karena CLI tidak menerima request HTTP, kita mengisi $_GET secara manual untuk mensimulasikan query string ?nama=Budi:
<?php
$_GET['nama'] = 'Budi';
function sapaDariGet(): string
{
return 'Halo, ' . htmlspecialchars($_GET['nama']) . '!';
}
echo sapaDariGet() . "\n";Output yang Dihasilkan:
Halo, Budi!Fungsi sapaDariGet() membaca $_GET['nama'] langsung tanpa deklarasi global dan berhasil mengembalikan Halo, Budi!. Satu detail keamanan ikut terbawa di sini: keluaran tersebut ditujukan untuk halaman HTML, sehingga teks dari pengunjung dilewatkan lebih dulu melalui htmlspecialchars() agar tag yang diselipkan pengunjung tidak dieksekusi browser. Meski superglobal selalu terjangkau, mengoper array sebagai parameter — seperti pola handler pada chapter pengantar — membuat fungsi lebih mudah diuji; gaya itulah yang dipakai contoh-contoh berikutnya.
$_REQUEST dan Urutan Penggabungan #
$_REQUEST adalah gabungan $_GET, $_POST, dan $_COOKIE yang dibangun PHP saat request dimulai, dengan urutan penggabungan yang diatur directive variables_order (bawaannya EGPCS — Environment, Get, Post, Cookie, Server). Bila ketiga sumber memakai nama kunci yang sama, sumber yang diproses belakangan menimpa yang lebih awal. Ada satu konsekuensi yang jarang disadari: $_REQUEST adalah snapshot awal request, bukan jendela hidup ke ketiga superglobal:
<?php
$_GET['tema'] = 'gelap';
var_dump(isset($_REQUEST['tema']));Output yang Dihasilkan:
bool(false)Baris pertama menulis ke $_GET pada saat runtime, namun isset($_REQUEST['tema']) tetap bool(false) — karena $_REQUEST sudah terbentuk sejak request dimulai, perubahan runtime pada $_GET tidak tercermin di dalamnya. Kami juga menguji urutan penggabungan pada request web nyata lewat skrip berikut:
<?php
// req.php — jalankan lewat server: php -S 127.0.0.1:8099
header('Content-Type: text/plain; charset=utf-8');
echo '$_GET[aksi] = ' . ($_GET['aksi'] ?? '(kosong)') . "\n";
echo '$_POST[aksi] = ' . ($_POST['aksi'] ?? '(kosong)') . "\n";
echo '$_COOKIE[aksi] = ' . ($_COOKIE['aksi'] ?? '(kosong)') . "\n";
echo '$_REQUEST[aksi] = ' . ($_REQUEST['aksi'] ?? '(kosong)') . "\n";Kami mengirim request dengan curl sambil membawa parameter ?aksi=dari_get, body POST aksi=dari_post, dan cookie aksi=dari_cookie sekaligus. Hasilnya konsisten pada dua percobaan: $_REQUEST['aksi'] berisi dari_cookie — nilai cookie menang karena huruf C diproses setelah G dan P pada urutan bawaan.
Batas Kepercayaan Data dari Luar #
Semua superglobal pada tabel di awal chapter berisi data dari luar program: pengunjung bisa mengetik query string apa pun di address bar, memodifikasi form lewat developer tools, mengubah cookie lewat penyimpanan browser, bahkan menulis header request apa adanya dengan curl. Termasuk di dalamnya banyak kunci $_SERVER yang berawalan HTTP_ — kunci tersebut dicerminkan dari header request, sehingga isinya juga kendali penuh pengunjung. Konsekuensinya: setiap nilai dari superglobal harus divalidasi sebelum dipakai. Berikut pola membaca parameter paginasi dengan disiplin:
<?php
function ambilHalaman(array $query, int $bawaan = 1): int
{
if (!isset($query['halaman'])) {
return $bawaan;
}
$halaman = filter_var($query['halaman'], FILTER_VALIDATE_INT, [
'options' => ['min_range' => 1, 'max_range' => 100],
]);
return $halaman === false ? $bawaan : $halaman;
}
$_GET['halaman'] = '7';
echo ambilHalaman($_GET) . "\n";
$_GET['halaman'] = 'abc';
echo ambilHalaman($_GET) . "\n";
$_GET['halaman'] = '150';
echo ambilHalaman($_GET) . "\n";
echo ambilHalaman([]) . "\n";Output yang Dihasilkan:
7
1
1
1Mari kita bedah pertahanan berlapisnya:
- Baris 3-5 (
isset): parameter yang tidak hadir langsung dialihkan ke nilai bawaan, sehingga tidak pernah munculWarning: Undefined array key. - Baris 7-9 (
filter_vardenganFILTER_VALIDATE_INT): nilai diperiksa harus berupa integer dalam rentang 1 sampai 100 — string'7'yang sah lolos menjadi integer7. - Baris 11: nilai yang gagal validasi —
'abc'yang bukan angka maupun'150'yang melampaui batas — tidak ditolak keras, melainkan digantikan nilai bawaan; pilihan yang wajar untuk paginasi. - Baris 20: pemanggil terakhir membuktikan array kosong pun tertangani.
Validasi masukan hanyalah separuh disiplin; separuh lainnya adalah meng-escape keluaran sesuai konteksnya (htmlspecialchars() untuk HTML) dan memakai prepared statement untuk SQL — keduanya dibangun tuntas pada Section Form Handling dan Validation
dan Web Security
.
filter_var dan filter_input #
Contoh di atas memakai filter_var() yang memvalidasi nilai apa pun yang diberikan. Extension filter punya saudara yang lebih spesifik untuk web: filter_input() membaca langsung dari data request asli dengan konstanta seperti INPUT_GET, INPUT_POST, INPUT_COOKIE, INPUT_SERVER, dan INPUT_ENV. Perilakunya menyimpan satu kejutan yang layak dibuktikan sendiri:
<?php
$_GET['nama'] = 'Budi';
$nilai = filter_input(INPUT_GET, 'nama', FILTER_DEFAULT);
var_dump($nilai);Output yang Dihasilkan:
NULLMeski baris pertama mengisi $_GET['nama'], hasilnya tetap NULL. Penjelasannya: filter_input() membaca data request asli yang disimpan PHP saat request dimulai — bukan array $_GET yang mungkin sudah dimodifikasi pada runtime. Pada request web sungguhan, filter_input(INPUT_GET, 'halaman', FILTER_VALIDATE_INT, ['options' => [...]]) mengembalikan hasil yang sama dengan pola ambilHalaman() di atas, dengan satu baris lebih ringkas dan kebal terhadap modifikasi $_GET entah dari mana. Pada CLI — seperti yang baru kita buktikan — data request asli memang kosong, itulah mengapa hasilnya NULL.
Struktur $_FILES untuk Unggahan #
Ketika form multipart/form-data dikirim, PHP menyimpan berkas yang ikut ke direktori sementara server lalu menyusun metadata-nya ke $_FILES. Struktur metadata per field unggahan terdiri dari lima kunci tetap. Karena CLI tidak menerima unggahan, kita periksa strukturnya lewat entri contoh yang dibekukan:
<?php
$files = [
'faktur' => [
'name' => 'faktur-juni.pdf',
'type' => 'application/pdf',
'tmp_name' => '/tmp/phpA1b2C3',
'error' => UPLOAD_ERR_OK,
'size' => 48213,
],
];
printf(
"Berkas: %s (%d byte, kode error %d)\n",
$files['faktur']['name'],
$files['faktur']['size'],
$files['faktur']['error'],
);Output yang Dihasilkan:
Berkas: faktur-juni.pdf (48213 byte, kode error 0)Makna tiap kunci: name adalah nama berkas versi pengirim, type adalah media type versi pengirim, tmp_name adalah lokasi berkas sementara di server, size ukuran dalam byte, dan error kode status unggahan — UPLOAD_ERR_OK bernilai 0 artinya sukses. Perhatikan bahwa name dan type sepenuhnya kata pengirim: keduanya bisa dipalsukan lewat request buatan, jadi jadikan keduanya data tampilan, bukan dasar keputusan keamanan. Berkas yang tersimpan di tmp_name hanya bertahan sampai request berakhir; untuk menyimpannya permanen, gunakan move_uploaded_file() — pembahasan lengkapnya ada pada Chapter Uploads dan File Storage
.
Membaca $_SERVER untuk Info Request #
Di lingkungan web, $_SERVER dipenuhi data request yang disiapkan server: method, URI, alamat klien, hingga header request yang dicerminkan dengan prefiks HTTP_. Isi kunci ini berbeda-beda antara server dan tidak semua kunci selalu hadir, sehingga pola yang sehat adalah membaca dengan nilai cadangan lewat operator ??. Fungsi kecil berikut merangkai URL skrip saat ini dari tiga kunci $_SERVER yang umum:
<?php
function urlSkripSaatIni(array $server): string
{
$skema = ($server['HTTPS'] ?? '') === 'on' ? 'https' : 'http';
return $skema . '://' . $server['HTTP_HOST'] . $server['REQUEST_URI'];
}
$serverWeb = [
'HTTPS' => 'on',
'HTTP_HOST' => 'www.contoh.com',
'REQUEST_URI' => '/produk?kategori=buku',
];
echo urlSkripSaatIni($serverWeb) . "\n";Output yang Dihasilkan:
https://www.contoh.com/produk?kategori=bukuFungsi urlSkripSaatIni() menerima array $_SERVER sebagai parameter biasa — pola handler yang sama seperti sebelumnya — lalu diuji dengan potongan $_SERVER web yang dibekukan. Kunci HTTPS bernilai string 'on' ketika request datang lewat TLS, HTTP_HOST mencerminkan header Host, dan REQUEST_URI berisi path beserta query string-nya. Hasil pengujian kami lewat built-in web server memperlihatkan pasangan kunci yang khas: REQUEST_METHOD = GET, REQUEST_URI = /info.php?halaman=2, dan QUERY_STRING = halaman=2.
Jejak register_globals #
Kisah ini menjelaskan mengapa disiplin kepercayaan di atas diperketat dari waktu ke waktu. Pada PHP versi lama — bawaan aktif sampai PHP 4 dan hanya dimatikan mulai PHP 5 — directive register_globals membuat setiap parameter request otomatis menjadi variabel global: query string ?id=42&authorized=1 langsung menciptakan $id dan $authorized di skrip. Kenyamanan itu berubah menjadi bencana ketika skrip menulis kode seperti if ($authorized) { ... } tanpa pernah menginisialisasi $authorized sendiri — pengunjung cukup menambahkan satu parameter untuk lolos pemeriksaan.
Directive tersebut deprecated pada PHP 5.3 dan dihapus total pada PHP 5.4, tetapi pelajarannya bertahan. Pertama, data dari luar harus diakses secara eksplisit melalui superglobal, bukan diinjeksikan diam-diam ke scope global. Kedua, setiap variabel yang dipakai untuk keputusan penting wajib diinisialisasi oleh kode kita sendiri. Dua prinsip itulah yang secara tidak langsung kita praktikkan sepanjang chapter: akses eksplisit lewat $_GET dan kawanannya, validasi eksplisit lewat extension filter.
Ringkasan #
Kini kita memahami peta lengkap superglobal dari sisi request web: sumber tiap array, urutan penggabungan $_REQUEST beserta sifat snapshot-nya, struktur $_FILES untuk unggahan, kunci-kunci $_SERVER yang sering dipakai, serta garis batas kepercayaan yang memisahkan data pengunjung dari keputusan aplikasi. Semua data ini tiba pada satu momen eksekusi skrip — dan momen itu hanyalah satu tahap dari perjalanan panjang. Chapter berikutnya menelusuri perjalanan lengkap tersebut pada Request Lifecycle
.