Fungsi-fungsi I/O yang telah kita gunakan sejauh ini — fopen(), file_get_contents(), hingga fwrite() — berjalan dengan perilaku bawaan yang sama pada setiap pemanggilan. Perilaku bawaan tersebut memadai untuk berkas lokal, tetapi menjadi masalah begitu target berpindah ke jaringan: permintaan HTTP tanpa batas waktu bisa menggantung berlama-lama, sebagian server menolak klien tanpa User-Agent, dan verifikasi sertifikat SSL perlu dikontrol secara eksplisit. Stream context adalah mekanisme PHP untuk mengatur semua perilaku tersebut. Pada chapter ini kita akan mempelajari cara membuat context, opsi-opsi yang paling sering dipakai, dan cara menyambungkannya ke fungsi-fungsi stream yang sudah Anda kenal.

Apa Itu Stream Context #

Stream context adalah kumpulan opsi yang menyertai sebuah operasi stream dan dibaca oleh wrapper sebelum stream dibuka. Secara teknis, context dibentuk dari array bertingkat: kunci tingkat pertama adalah nama wrapper (misalnya http atau ssl), kunci tingkat kedua adalah nama opsi, dan nilainya adalah pengaturan yang kita inginkan. Struktur bertingkat ini penting karena opsi dengan nama mirip bisa berbeda makna pada wrapper yang berbeda.

Context diterima sebagai parameter opsional terakhir pada banyak fungsi filesystem: fopen(), file_get_contents(), file(), file_put_contents(), copy(), hingga mkdir(). Jika kita tidak memberikan context, PHP memakai context default bawaan — dan seperti akan kita lihat di bagian akhir chapter, context default tersebut bisa kita ubah.

Membuat Context dengan stream_context_create #

Fungsi stream_context_create() menerima array opsi bertingkat lalu mengembalikan resource context. Contoh berikut menyiapkan context untuk sebuah permintaan HTTP POST dengan batas waktu lima detik, lengkap dengan pengaturan verifikasi SSL:

php
<?php
$context = stream_context_create([
    'http' => [
        'method' => 'POST',
        'header' => "Content-Type: application/json\r\nUser-Agent: KursusPHP/1.0",
        'timeout' => 5,
        'ignore_errors' => true,
    ],
    'ssl' => [
        'verify_peer' => true,
        'verify_peer_name' => true,
    ],
]);

echo json_encode(
    stream_context_get_options($context),
    JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES
), "\n";

Output yang Dihasilkan:

text
{
    "http": {
        "method": "POST",
        "header": "Content-Type: application/json\r\nUser-Agent: KursusPHP/1.0",
        "timeout": 5,
        "ignore_errors": true
    },
    "ssl": {
        "verify_peer": true,
        "verify_peer_name": true
    }
}

Mari kita bedah kode di atas baris per baris:

  1. Array 'http': kumpulan opsi untuk wrapper http. Opsi method mengatur metode HTTP, header menampung baris header tambahan yang dipisah \r\n, timeout membatasi durasi operasi baca dalam detik, dan ignore_errors membuat file_get_contents() tetap mengembalikan body respons meskipun server menjawab status 4xx atau 5xx.
  2. Array 'ssl': opsi untuk lapisan TLS ketika URL menggunakan https://. verify_peer dan verify_peer_name sama-sama bernilai true — ini memang nilai bawaannya, tetapi menuliskannya secara eksplisit membuat niat kode lebih jelas.
  3. stream_context_get_options(): membaca kembali seluruh opsi yang tersimpan di dalam context — berguna untuk memastikan konfigurasi sudah benar sebelum context dipakai.
  4. json_encode() dengan JSON_PRETTY_PRINT: kita pakai hanya untuk menampilkan struktur context secara rapi; pada pemakaian nyata context langsung diteruskan ke fungsi stream.

Perhatikan bahwa satu context boleh berisi opsi untuk beberapa wrapper sekaligus. Opsi untuk wrapper yang tidak terlibat dalam operasi akan diabaikan tanpa error.

Opsi yang Sering Dipakai #

Dua kelompok opsi berikut paling sering muncul dalam kode sehari-hari:

WrapperOpsiKegunaan
httpmethodMetode HTTP: GET, POST, HEAD, dan sebagainya
httpheaderHeader tambahan, dipisah \r\n
httptimeoutBatas waktu operasi baca/tulis socket, dalam detik
httpignore_errorsTetap baca body meski status respons 4xx/5xx
httpmax_redirectsJumlah maksimum redirect yang diikuti
sslverify_peerVerifikasi sertifikat server
sslverify_peer_nameCocokkan nama host dengan sertifikat
sslallow_self_signedIzinkan sertifikat self-signed, hanya untuk lingkungan pengembangan

Memakai Context di file_get_contents #

file_get_contents() menerima context pada argumen ketiganya. Pola lengkapnya terlihat pada contoh berikut, yang mengunduh sebuah berkas teks dari server publik:

php
<?php
$context = stream_context_create([
    'http' => [
        'method' => 'GET',
        'header' => "User-Agent: KursusPHP/1.0\r\nAccept: text/plain",
        'timeout' => 5,
    ],
]);

$isi = file_get_contents('https://www.php.net/robots.txt', false, $context);

if ($isi === false) {
    echo "Permintaan gagal\n";
} else {
    echo "Total byte yang diterima: " . strlen($isi) . "\n";
}

Contoh di atas membutuhkan akses jaringan sehingga tidak dieksekusi otomatis di halaman ini, tetapi mudah Anda coba sendiri. Saat kami mengujinya secara manual, berkas robots.txt berhasil diunduh dan jumlah byte-nya tercetak — angka pastinya berubah sewaktu-waktu karena isi berkas di server ikut diperbarui, itulah sebabnya kami tidak mencantumkannya sebagai output tetap.

Tiga perilaku penting dari contoh tersebut:

  1. Argumen kedua false menonaktifkan pencarian di include_path; context selalu duduk di argumen ketiga.
  2. timeout => 5 memastikan permintaan yang macet berhenti setelah lima detik. Tanpa context, operasi jaringan mengikuti default_socket_timeout yang bernilai 60 detik — terlalu lama untuk sebuah permintaan web.
  3. $http_response_header — variabel ini otomatis dibuat oleh PHP setelah pemanggilan sukses dan berisi array baris header respons (status line beserta seluruh headernya). Saat diuji, array tersebut terisi lebih dari dua puluh elemen sehingga kita bisa memeriksa kode status tanpa ekstensi cURL.

Context Default untuk Semua Stream #

Kadang kita ingin satu pengaturan berlaku untuk seluruh operasi HTTP dalam skrip tanpa harus membuat context berulang-ulang. Fungsi stream_context_set_default() mengubah context bawaan yang dipakai PHP ketika tidak ada context eksplisit:

php
<?php
stream_context_set_default([
    'http' => [
        'timeout' => 10,
        'header' => 'User-Agent: KursusPHP/1.0',
    ],
]);

// Semua operasi stream http selanjutnya memakai opsi di atas
$default = stream_context_get_default();

echo json_encode(
    stream_context_get_options($default),
    JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES
), "\n";

Output yang Dihasilkan:

text
{
    "http": {
        "timeout": 10,
        "header": "User-Agent: KursusPHP/1.0"
    }
}

stream_context_get_default() mengembalikan context bawaan tersebut, dan stream_context_get_options() membuktikan bahwa opsi kita sudah menempel padanya. Mulai titik ini, setiap file_get_contents('https://...') tanpa context eksplisit akan membawa User-Agent dan batas waktu sepuluh detik.

Context Bersama fopen dan fgets #

fopen() menerima context pada argumen keempatnya. Kombinasi ini berguna ketika kita ingin membaca respons jaringan secara bertahap dengan fgets() atau fread(), alih-alih memuat seluruh isi ke memori sekaligus seperti file_get_contents():

php
<?php
$context = stream_context_create([
    'http' => ['timeout' => 5],
]);

$handle = fopen('https://www.php.net/robots.txt', 'r', false, $context);
if ($handle === false) {
    exit("Gagal membuka URL\n");
}

$jumlahBaris = 0;
while (($baris = fgets($handle)) !== false) {
    $jumlahBaris++;
}

echo "Jumlah baris: $jumlahBaris\n";
fclose($handle);

Sama seperti contoh sebelumnya, blok ini memerlukan jaringan sehingga Anda perlu menjalankannya sendiri — saat kami mencobanya, seluruh baris robots.txt terbaca satu per satu dan terhitung tiga belas baris. Pola pembacaannya identik dengan membaca berkas lokal: stream yang dibuka oleh fopen() bersifat seragam, terlepas dari sumbernya berkas di disk atau respons HTTP. Perbedaannya hanya ada pada argumen keempat fopen() yang kita isi dengan context pembawa timeout, sehingga proses tidak pernah menggantung lebih dari lima detik saat server lambat merespons.

Ringkasan #

Stream context melengkapi API stream dengan lapisan konfigurasi: stream_context_create() membungkus opsi per wrapper, fungsi-fungsi seperti file_get_contents() dan fopen() menerimanya lewat parameter tambahan, dan stream_context_set_default() mengatur konfigurasi global. Dengan bekal ini, kita siap membongkar mesin di balik URL seperti http:// dan data:// — yaitu stream wrapper — pada chapter berikutnya.

Referensi #