Membaca berkas hanyalah setengah cerita: aplikasi juga perlu menciptakan berkas — menyimpan laporan, membuat berkas konfigurasi, menulis cache, hingga menghasilkan file CSV untuk diunduh pengguna. PHP menyediakan dua jalur utama untuk menulis, yaitu fungsi serba-guna file_put_contents() dan kombinasi fopen()–fwrite()–fclose() yang memberi kendali penuh, dan keduanya punya tempatnya masing-masing. Pada chapter ini kita akan memakai keduanya, membedah mode pembukaan w, a, dan x yang menentukan nasib isi lama, lalu menutup dengan topik fflush() serta permission bawaan berkas baru. Seperti chapter sebelumnya, setiap contoh membersihkan berkas latihannya sendiri di akhir skrip.

Fungsi file_put_contents() menerima path dan string data, lalu melakukan urutan lengkap — membuat berkas bila perlu, menulis data, menutup berkas — dalam satu panggilan. Nilai kembaliannya adalah jumlah byte yang berhasil ditulis, atau false bila gagal:

php
<?php
$berkas = __DIR__ . '/pesan.txt';
$jumlahByte = file_put_contents($berkas, "Halo, Budi!\n");

echo "Tertulis: $jumlahByte byte\n";
echo file_get_contents($berkas);

unlink($berkas);

Output yang Dihasilkan:

text
Tertulis: 12 byte
Halo, Budi!

Perhatikan bahwa jumlah byte yang dilaporkan — 12 — mencakup seluruh string termasuk karakter \n di ujungnya. Sifat penting yang perlu diingat: setiap panggilan file_put_contents() menimpa seluruh isi lama dari awal berkas. Perhatikan apa yang terjadi ketika fungsi ini dipanggil dua kali pada berkas yang sama:

php
<?php
$berkas = __DIR__ . '/catatan.txt';

file_put_contents($berkas, "Versi pertama\n");
file_put_contents($berkas, "Versi kedua\n");

echo file_get_contents($berkas);

unlink($berkas);

Output yang Dihasilkan:

text
Versi kedua

Isi akhir hanya memuat Versi kedua — teks Versi pertama hilang total karena penulisan kedua menghapus isi lama lebih dulu. Jika yang Anda butuhkan adalah menambahkan data di akhir berkas tanpa menghapus yang lama, gunakan flag FILE_APPEND yang akan kita bahas tuntas pada chapter Append dan File Locking.

Untuk penulisan bertahap — misalnya menulis baris demi baris hasil loop — kombinasikan fopen() mode 'w', fwrite(), dan fclose(). Mode 'w' membuka berkas untuk ditulis dan langsung mengosongkan (truncate) isi lamanya bila berkas sudah ada, atau membuat berkas baru bila belum ada:

php
<?php
$berkas = __DIR__ . '/profil.txt';

$handle = fopen($berkas, 'w');
if ($handle === false) {
    exit("Gagal membuka berkas untuk ditulis.\n");
}

fwrite($handle, "Nama: Siti\n");
fwrite($handle, "Kota: Bandung\n");
fclose($handle);

echo file_get_contents($berkas);

unlink($berkas);

Output yang Dihasilkan:

text
Nama: Siti
Kota: Bandung

Mari kita bedah alurnya:

  1. Baris 3 (fopen($berkas, 'w')): membuka (atau membuat) berkas untuk ditulis dan sekaligus mengosongkan isinya; nilai kembalian berupa stream resource yang menjadi pegangan penulisan.
  2. Baris 4-6: pemeriksaan $handle === false menjaga skrip agar tidak meneruskan penulisan ketika pembukaan berkas gagal — tanpa pemeriksaan ini, fwrite() berikutnya berujung pada error fatal.
  3. Baris 8-9 (fwrite($handle, ...)): menulis string ke posisi penunjuk saat ini; kedua panggilan menumpuk secara berurutan karena penunjuk bergerak maju setiap kali data ditulis.
  4. Baris 10 (fclose($handle)): menutup berkas dan memastikan semua data benar-benar tersimpan; melewatkan langkah ini berisiko kehilangan data saat skrip berakhir secara tidak normal.

Mode Pembukaan untuk Menulis: w, a, dan x #

Mode 'w' bukan satu-satunya pilihan, dan memilih mode yang salah adalah salah satu penyebab kehilangan data yang paling klasik. Tabel berikut merangkum seluruh mode pembukaan yang relevan untuk penulisan:

ModeBerkas sudah adaBerkas belum adaPosisi penunjuk
wisi lama dihapusberkas dibuatawal
w+isi lama dihapus, bisa dibaca jugaberkas dibuatawal
aisi lama dipertahankan, tulis di akhirberkas dibuatakhir
a+isi lama dipertahankan, baca dan tulisberkas dibuatakhir
xgagal — false + Warningberkas dibuatawal
x+gagal — false + Warningberkas dibuatawal

Mode x sengaja dirancang untuk skenario “buat berkas baru tanpa risiko menimpa”: jika berkas ternyata sudah ada, fopen() mengembalikan false dan memicu Warning dengan pesan Failed to open stream: File exists, alih-alih menghapus isi lama sebagaimana w. Pola aman untuk memakainya adalah memeriksa hasil pembukaan seperti ini:

php
<?php
$berkas = __DIR__ . '/konfigurasi.txt';

if (is_file($berkas)) {
    echo "Berkas sudah ada — mode 'x' menolak menimpa.\n";
} else {
    $handle = fopen($berkas, 'x');
    fwrite($handle, "mode=produksi\n");
    fclose($handle);
    echo "Berkas baru berhasil dibuat.\n";
}

unlink($berkas);

Output yang Dihasilkan:

text
Berkas baru berhasil dibuat.

Data dalam aplikasi sering sudah berbentuk array, misalnya daftar tugas atau baris laporan. Karena fwrite() dan file_put_contents() hanya menerima string, gunakan implode() untuk menggabungkan array menjadi teks berformat baris:

php
<?php
$berkas = __DIR__ . '/tugas.txt';
$daftar = ['Belajar PHP', 'Menulis berkas', 'Membuat proyek'];

$isi = implode("\n", $daftar) . "\n";
file_put_contents($berkas, $isi);

foreach (file($berkas, FILE_IGNORE_NEW_LINES) as $nomor => $tugas) {
    echo ($nomor + 1) . ". $tugas\n";
}

unlink($berkas);

Output yang Dihasilkan:

text
1. Belajar PHP
2. Menulis berkas
3. Membuat proyek

Baris $isi = implode("\n", $daftar) . "\n" menghasilkan "Belajar PHP\nMenulis berkas\nMembuat proyek\n" — setiap elemen dipisah \n, dan "\n" tambahan di akhir memastikan baris terakhir juga diakhiri baris baru sebagaimana konvensi berkas teks Unix. Untuk membaca kembali, kita memanfaatkan file() dengan flag FILE_IGNORE_NEW_LINES dari chapter sebelumnya, lalu menomori setiap baris lewat key dari foreach.

Mem-flush Data dengan fflush #

Fungsi fflush() memaksa semua data yang masih berada di buffer stream PHP untuk segera diteruskan ke sistem operasi. Pada berkas lokal PHP modern, penulisan biasanya memang langsung diteruskan, tetapi fflush() tetap menjadi jaminan eksplisit — pola ini penting saat Anda bekerja dengan stream yang benar-benar di-buffer (misalnya stream jaringan) atau ingin memastikan data sudah berada di tangan sistem operasi sebelum melanjutkan logika lain:

php
<?php
$berkas = __DIR__ . '/sesi.txt';

$handle = fopen($berkas, 'w');
fwrite($handle, "Sesi dimulai\n");
fflush($handle); // pastikan baris pertama sudah diteruskan ke sistem operasi

fwrite($handle, "Sesi berakhir\n");
fclose($handle); // fclose juga otomatis mem-flush sisa data

echo file_get_contents($berkas);

unlink($berkas);

Output yang Dihasilkan:

text
Sesi dimulai
Sesi berakhir

Permission File Baru dan umask #

Setiap berkas baru yang diciptakan PHP mendapat permission dasar 0666 (baca-tulis untuk semua pihak), lalu sistem operasi “menyaring"nya dengan umask — sekumpulan bit yang otomatis dicabut dari permission dasar tersebut. Rumusnya: permission akhir = 0666 & ~umask. Kita bisa melihat proses ini langsung:

php
<?php
$berkas = __DIR__ . '/berkas-baru.txt';
file_put_contents($berkas, "isi berkas\n");

echo "umask aktif: " . sprintf('%04o', umask()) . "\n";
echo "Permission berkas baru: " . sprintf('%04o', fileperms($berkas) & 0777) . "\n";

unlink($berkas);

Output yang Dihasilkan:

text
umask aktif: 0002
Permission berkas baru: 0664

Pada lingkungan eksekusi chapter ini umask bernilai 0002, sehingga 0666 & ~0002 menghasilkan permission 0664 — bit tulis untuk “other” tercabut. Pada server yang umumnya memakai umask 0022, hasilnya adalah 0644, angka yang mungkin sering Anda lihat di tutorial. Angka permission ini akan kita baca tuntas maknanya pada chapter File Permissions; untuk sekarang, cukup pahami bahwa nilai umask lingkungan ikut menentukan permission berkas baru Anda.

Ringkasan #

file_put_contents() adalah pintu cepat untuk menulis satu string utuh dengan perilaku timpa-menimpa yang perlu diwaspadai, sedangkan fopen()–fwrite()–fclose() memberi kendali bertahap untuk penulisan yang panjang. Mode pembukaan menentukan segalanya: w menghapus isi lama, a menambahkan di akhir, dan x menolak menimpa berkas yang sudah ada. Ditambah implode() untuk mengubah array menjadi baris teks, fflush() untuk memaksa data keluar dari buffer, dan pemahaman awal tentang umask, kita sudah bisa menciptakan berkas secara aman. Chapter berikutnya menggali lebih dalam perilaku menambahkan data — dan masalah serius yang muncul ketika banyak proses menulis ke berkas yang sama: append dan file locking.

Referensi #