16 June 2008

PHP: Menyembunyikan Path File Download

Hah, mulai lagi. Sebagai pemanasan dimulai dengan yang mudah dulu,dalam hal pengamanan download file. Tujuannya adalah dengan membuatsebuah script download tanpa harus langsung diarahkan ke file tujuanyang bisa diambil user. Langkah yang paling primitif dalam menyediakan download file adalah dengan anchor hyperlink.
<a href='Arsip/Laporan-jun-08.pdf' >download</a>
Dengan hyperlink diatas, file yang disediakan di server akan dikirimkan untuk diambil, misalkan dengan fullpath dari file tersebut'/var/www/Arsip/Laporan-jun-08.pdf'. Sekarang dengan fasilitas headerdari php, kita bisa menyembunyikan relatif sekaligus fullpath dari file.
Dengan menyembunyikan url file, user tidak perlu mengetahui path asli dari file, download dialog cuma menampilkan bahwa file diambil darisebuah file php.

Dengan tujuan dan keuntungan dari metode ini adalah:
- Lebih menyamarkan susunan direktori dari htdocs server.
- Memaksa browser untuk langsung menyediakan download dialog, tanpa terlebih dahulu melihat tipe file yang didownload.
Pada direct url, browser terlebih dahulu melihat plugin pembuka fileyang ada didalam dirinya, dan membuka, bukan lagi mendownload file, apabila memungkinkan. Misalkan kita menyediakan url dengan tipe filepdf, maka browser mendeteksi mime-type-nya sebagai application/pdf,membuka internal viewer untuk pdf, misalkan berupa plugin dari acrobatreader. Tentu ini menjengkelkan bagi user karena lebih mudah kalau filedidownload terlebih dahulu setelah itu file yang sudah tersimpan dilain waktu.
Dengan menggunakan hiding url, browser tidak bisa melakukan deteksitipe file karena mime-type-nya sudah disamarkan sebagai octet-stream,bahkan apabila kita memberikan download untuk file dengan tipe yangbisa dibuka langsung oleh browser, misalkan html, php, atau xml.
- Tidak menyediakan langsung alamat aslinya, artinya lebih menyulitkanuser yang menggunakan download manager yang bersifat multiple downloadsekaligus yang bisa memperlambat user yang lain. Url yang diperlihatkankepada user adalah url dari file php dengan skrip hiding url ini.
- Dengan memanfaatkan session, kita bisa mengatur hanya user yang sudahmelakukan autentifikasi yang bisa mengambil file yang kita sediakan.
- kita bisa menyediakan url file yang bersifat valid untuk sementara,dengan penambahan angka random dalam url, dengan tanggal expired yang bisa ditentukan.
- Bisa meyediakan fasilitas php yang lain, selain session dan random,misalkan, integrasi dengan database untuk manajemen dan statistikdownload, download file yang di-generate secara dinamis melalui imagecreate, memanfaatkan variabel $_POST, dll. Tergantung kreatifitas aja deh.

Fungsi dasar yang digunakan adalah:
- ob, untuk melakukan output buffering, mengumpulkan beberapa data untuk dikirimkan semua sekaligus ke user secara langsung.
- header, untuk menentukan header dari respon server. header, artinyaskrip ini harus diletakkan di paling atas dari skrip yang lain. Tidak boleh didahului dengan header yang lain dan respon server lainnya.Misalkan didahului oleh echo atau tag html, bahkan harus diatas<html> sekalipun. HMMM, sekarang masalah header agak sedikitpanjang seritanya, makanya coba dulu beberapa hal.

+ Contoh dari penggunaan header adalah untuk melakukan redirect dengan cara berikut:
<?
header('Location: http://www.om4gus.blogspot.com/');
?>


+ kemudian letakkan skrip diatas yang lain, tambahkan exit untuk memastikan tidak ada respon lainnya yang dikirimkan:
<?
header('Location: http://www.om4gus.blogspot.com/');
exit();
?>


+ Header yang didahului respon lainnya akan mengembalikan error berikut:
Warning: Cannot add header information - headers already sent
contohnya untuk :
<html>
<?
header('Location: http://www.om4gus.blogspot.com/');
?>


untuk memastikan tidak ada error yang berhubungan dengan header tersebut cek isi header terlebih dahulu:
if (!headers_sent()) {
header('Location: http://www.om4gus.blogspot.com/');
exit;
}


Sekarang Alternatif untuk redirect tanpa harus memikirkan header segala macam, bisa diletakkan dibagian manapun, adalah dengan menggunakan js
<?
echo "<script>location.assign('http://www.om4gus.blogspot.com/')</script>";
exit();
?>


atau memaksa user untuk kembali ke halaman sebelumnya dengan back(), forward untuk halaman berikutnya:
<? echo "<script>history.back();</script>"; ?>

Tambahan, karena perintah header selalu diletakkan di paling atas, usahakan selalu menggunakan file php yang terpisah dari file lain, dengan keperluan khusus untuk menangani download file. Atau kalaupun bersamaan dengan lainnya, gunakan sebuah kondisi, misalkan pengecekan dengan variabel session atau get, sehingga hanya dijalankan karena kondisi tertentu.

Sekarang kembali ke topik utama, masalah implementasi.....
Tinggal membuat hiperlink yang diarahkan ke sebuah php, yang mentrigger terjadinya proses download.
<html>
<a href='dl.php' />Download</a>
</html>


Yup, simple! ingat, ke php, bukan file aslinya seperti sebelumnya, <a href='Arsip/Laporan-jun-08.pdf'>, kemudian buat file pdf sesuai alamat tersebut untuk percobaan selanjutnya.


Untuk Source dari file php yang dipanggil, coba satu-persatu contoh implementasi berikut:
Fungsi dasar untuk melakukan hiding url fullpath, dengan tetap menggunakan nama file asli dari file yang didownload:
<?
//file dengan nama dl.php
//pembuatan fungsi
function download($url){
ob_start();
$mm_type="application/octet-stream";
header("Cache-Control: public, must-revalidate");
header("Pragma: File Download");
header("Content-Type: $mm_type");
header("Content-Length: ".(string)(filesize($url)));
header('Content-Disposition: attachment; filename="'.basename($url).'"');
header("Content-Transfer-Encoding: binary\n");
ob_end_clean();
readfile($url);
exit();
}
//Contoh pemanggilan
if(file_exists("Arsip/Laporan-jun-08.pdf"))
download("Arsip/Laporan-jun-08.pdf");
?>


Fungsi dengan melakukan hiding fullpath, sekaligus memberikan nama file falsu sebagai default save name:
<?
//pembuatan fungsi
function download($url,$fakename){
ob_start();
$mm_type="application/octet-stream";
header("Cache-Control: public, must-revalidate");
header("Pragma: File Download");
header("Content-Type: $mm_type");
header("Content-Length: ".(string)(filesize($url)));
header('Content-Disposition: attachment; filename="'.$fakename.'"');
header("Content-Transfer-Encoding: binary\n");
ob_end_clean();
readfile($url);
exit();
}
//Contoh pemanggilan
if(file_exists("Arsip/Laporan-jun-08.pdf"))
download("Arsip/Laporan-jun-08.pdf","Laporan-current.pdf");
?>



Sekarang, contoh yang menggunakan session
<?
session_start();
function download(){
$url=$_SESSION[user]."/Laporan-jun-08.pdf";
ob_start();
$mm_type="application/octet-stream";
header("Cache-Control: public, must-revalidate");
header("Pragma: File Download");
header("Content-Type: $mm_type");
header("Content-Length: ".(string)(filesize($url)));
header('Content-Disposition: attachment; filename="'.$_SESSION[user]."_".basename($url).'"');
header("Content-Transfer-Encoding: binary\n");
ob_end_clean();
readfile($url);
exit();
}
if(isset($_SESSION[user]))
download();

if(isset($_POST[uname])){
if($_POST[uname]=="me"&&$_POST[pass]=="em"){
session_register(user);
$_SESSION[user]="Aku";
//<script>location.assign('http://www.om4gus.blogspot.com/')</script>
}else if($_POST[uname]=="mine"&&$_POST[pass]=="enim"){
session_register(user);
$_SESSION[user]="Saya";
} header('Location: '.$_SERVER[PHP_SELF]);
}else{
?>
<form method=POST>
<center>
<input type=text name=uname><br/>
<input type=password name=pass><br/>
<small>coba, username me passwordnya em</small><br/>
<input type=submit name=login value="login untuk mendownload">
<center>
</form>
<?
}
?>


That's it. Gampang khan?

5 °C:

PORTABLE SOFTWARE said...
This comment has been removed by a blog administrator.
om4gus said...

@ PORTABLE SOFTWARE
MAKASIH, ORANG YANG HEBAT SEPERTI ANDA SUDAH MENYEMPATKAN DIRI UNTUK MENINGGALKAN KOMENTAR DI BLOG SAYA YANG JELEK INI. OH IYA, NERAKA JAHANAMNYA SEBELAH MANA MAS? SIAPA TAU KITA TETANGGAAN

mahjonk said...

Om, saya udah coba script di atas.
Yg 1 dan 2, yg pakai session belum.
Itu kalau di localhost bisa jalan tapi setelah saya upload koq gak bisa ya ..??
Memang bener dialog box untuk download tampil, tapi begitu file yg didownload dibuka selalu error. Dan ukurannya sama, 135 byte.
Itu kenapa om, bagaimana benerinnya ..??
Terima kasih

om4gus said...

@mahjonk
Kasusnya bisa saja sama dengan yang ini , coba set output typenya.
Hal ini disebabkan konfigurasi apache server yang berbeda. Lakukan tes dengan file dan server yang berbeda.

Genflix said...

Nah, gan... kalau filenya bentuk video semacam flv gimana ya.

Post a Comment