Cara memaksa mengunduh file dengan PHP


125

Saya ingin meminta file untuk diunduh saat pengguna mengunjungi halaman web dengan PHP. Saya pikir itu ada hubungannya dengan file_get_contents, tetapi saya tidak yakin bagaimana menjalankannya.

$url = "http://example.com/go.exe";

Setelah mengunduh file header(location)dengannya tidak mengarahkan ke halaman lain. Itu berhenti begitu saja.


kemungkinan duplikat pengunduhan halaman paksa di php
hakre

Jawaban:


234

Baca dokumen tentang readfile fungsi PHP bawaan

$file_url = 'http://www.myremoteserver.com/file.exe';
header('Content-Type: application/octet-stream');
header("Content-Transfer-Encoding: Binary"); 
header("Content-disposition: attachment; filename=\"" . basename($file_url) . "\""); 
readfile($file_url); 

Pastikan juga untuk menambahkan jenis konten yang tepat berdasarkan aplikasi file / zip, aplikasi / pdf, dll. - tetapi hanya jika Anda tidak ingin memicu dialog simpan-sebagai.


6
Mengapa itu diperlukan?
john

Maksud saya jika itu selain file .exe daripada hanya. Lain ini seharusnya berfungsi dengan baik.
Pit Digger

7
Jangan lupa untuk menyiram ;-) ob_clean (); menyiram(); / * sebelum * / readfile ($ file_url);
Abu

Jadi jika Anda memiliki file besar 10GB php mencoba memuat seluruh file itu?
GDY

exit () harus dipanggil di akhir untuk menghindari potensi masalah (berbicara dari pengalaman :-)
ykay mengatakan Reinstate Monica

42
<?php
$file = "http://example.com/go.exe"; 

header("Content-Description: File Transfer"); 
header("Content-Type: application/octet-stream"); 
header("Content-Disposition: attachment; filename=\"". basename($file) ."\""); 

readfile ($file);
exit(); 
?>

Atau, jika file tidak dapat dibuka dengan browser, Anda dapat menggunakan Locationheader:

<?php header("Location: http://example.com/go.exe"); ?>

1
nama file di header Anda tidak boleh $file(yang berisi bagian http) tetapi nama file yang valid.
Fabio

1
Tidak ada jenis media aplikasi / unduh paksa ; gunakan application / octet-stream sebagai gantinya.
Gumbo

bekerja sangat bagus! Tetapi menambahkan 'ke nama file yang disimpan. Silakan gunakan: filename = ". Basename ($ file));
harry4516

@ harry4516 dimodifikasi menurut temuan Anda
Marek Sebera

Tidak bekerja sayang dalam kasus gambar png untuk saya. Terima kasih.
Kamlesh

40
header("Content-Type: application/octet-stream");
header("Content-Transfer-Encoding: Binary");
header("Content-disposition: attachment; filename=\"file.exe\""); 
echo readfile($url);

benar

atau lebih baik untuk jenis file exe

header("Location: $url");

@Fabio: Akan menambahkan lebih banyak detials
genesis

Itu sangat mudah. Berhasil. Untuk apa file-Get_contents itu? Hanya penasaran. Terima kasih.
john

untuk mengunduhnya ke server Anda
kejadian

10
Hapus saja 'echo' sebelum 'readfile ()' karena nilai yang dikembalikan ditetapkan sebagai "Mengembalikan jumlah byte yang dibaca dari file. Jika terjadi kesalahan, FALSE dikembalikan dan kecuali fungsi itu dipanggil sebagai @readfile (), pesan kesalahan dicetak. ". Jadi Anda akan berakhir dengan konten file + bilangan bulat di akhir konten.
Mladen B.

22

Tampilkan file Anda terlebih dahulu dan atur nilainya menjadi url.

index.php

<a href="download.php?download='.$row['file'].'" title="Download File">

download.php

<?php
/*db connectors*/
include('dbconfig.php');

/*function to set your files*/
function output_file($file, $name, $mime_type='')
{
    if(!is_readable($file)) die('File not found or inaccessible!');
    $size = filesize($file);
    $name = rawurldecode($name);
    $known_mime_types=array(
        "htm" => "text/html",
        "exe" => "application/octet-stream",
        "zip" => "application/zip",
        "doc" => "application/msword",
        "jpg" => "image/jpg",
        "php" => "text/plain",
        "xls" => "application/vnd.ms-excel",
        "ppt" => "application/vnd.ms-powerpoint",
        "gif" => "image/gif",
        "pdf" => "application/pdf",
        "txt" => "text/plain",
        "html"=> "text/html",
        "png" => "image/png",
        "jpeg"=> "image/jpg"
    );

    if($mime_type==''){
        $file_extension = strtolower(substr(strrchr($file,"."),1));
        if(array_key_exists($file_extension, $known_mime_types)){
            $mime_type=$known_mime_types[$file_extension];
        } else {
            $mime_type="application/force-download";
        };
    };
    @ob_end_clean();
    if(ini_get('zlib.output_compression'))
    ini_set('zlib.output_compression', 'Off');
    header('Content-Type: ' . $mime_type);
    header('Content-Disposition: attachment; filename="'.$name.'"');
    header("Content-Transfer-Encoding: binary");
    header('Accept-Ranges: bytes');

    if(isset($_SERVER['HTTP_RANGE']))
    {
        list($a, $range) = explode("=",$_SERVER['HTTP_RANGE'],2);
        list($range) = explode(",",$range,2);
        list($range, $range_end) = explode("-", $range);
        $range=intval($range);
        if(!$range_end) {
            $range_end=$size-1;
        } else {
            $range_end=intval($range_end);
        }

        $new_length = $range_end-$range+1;
        header("HTTP/1.1 206 Partial Content");
        header("Content-Length: $new_length");
        header("Content-Range: bytes $range-$range_end/$size");
    } else {
        $new_length=$size;
        header("Content-Length: ".$size);
    }

    $chunksize = 1*(1024*1024);
    $bytes_send = 0;
    if ($file = fopen($file, 'r'))
    {
        if(isset($_SERVER['HTTP_RANGE']))
        fseek($file, $range);

        while(!feof($file) &&
            (!connection_aborted()) &&
            ($bytes_send<$new_length)
        )
        {
            $buffer = fread($file, $chunksize);
            echo($buffer);
            flush();
            $bytes_send += strlen($buffer);
        }
        fclose($file);
    } else
        die('Error - can not open file.');
    die();
}
set_time_limit(0);

/*set your folder*/
$file_path='uploads/'."your file";

/*output must be folder/yourfile*/

output_file($file_path, ''."your file".'', $row['type']);

/*back to index.php while downloading*/
header('Location:index.php');
?>

2
Darimana kamu mendapatkan ini? Tampaknya kuat
Axel A. García

@ jundell-agbo menarik dan untuk file crt?
fralbo

Ini juga berfungsi untuk file yang sangat besar. Solusi yang bagus. Tapi` $ chunksize = 1 * (1024 * 1024); `lambat. Saya mencoba dengan beberapa nilai dan melihat bahwa `$ chunksize = 8 * (1024 * 1024);` menggunakan semua bandwidth yang tersedia.
Lingga

16

Jika Anda harus mengunduh file dengan ukuran lebih besar dari batas memori yang diizinkan ( memory_limitpengaturan ini), yang akan menyebabkan PHP Fatal error: Allowed memory size of 5242880 bytes exhaustedkesalahan, Anda dapat melakukan ini:

// File to download.
$file = '/path/to/file';

// Maximum size of chunks (in bytes).
$maxRead = 1 * 1024 * 1024; // 1MB

// Give a nice name to your download.
$fileName = 'download_file.txt';

// Open a file in read mode.
$fh = fopen($file, 'r');

// These headers will force download on browser,
// and set the custom file name for the download, respectively.
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . $fileName . '"');

// Run this until we have read the whole file.
// feof (eof means "end of file") returns `true` when the handler
// has reached the end of file.
while (!feof($fh)) {
    // Read and output the next chunk.
    echo fread($fh, $maxRead);

    // Flush the output buffer to free memory.
    ob_flush();
}

// Exit to make sure not to output anything else.
exit;

Saya baru saja mencoba ini dan itu mematikan server saya. Menulis sejumlah besar kesalahan ke log saya.
Daniel Williams

Akan berguna untuk mengetahui tentang apa log itu.
Parziphal

Ya maaf, file log menjadi sangat besar sehingga saya harus membuangnya begitu saja, jadi saya tidak bisa melihatnya.
Daniel Williams

Saya harus menyiapkan sesuatu seperti ini di server yang aksesnya sangat terbatas. Skrip unduhan saya terus mengarah ke halaman beranda dan saya tidak tahu mengapa. Sekarang saya tahu masalahnya adalah kesalahan memori dan kode ini menyelesaikannya.
Gavin

Jika Anda baru saja menggunakan ob_flush()mungkin ada kesalahan: ob_flush (): gagal membersihkan buffer. Tidak ada buffer untuk disiram . membungkusnya dengan if (ob_get_level() > 0) {ob_flush();}(Referensi stackoverflow.com/a/9182133/128761 )
vee

11

Modifikasi jawaban yang diterima di atas, yang juga mendeteksi jenis MIME dalam runtime:

$finfo = finfo_open(FILEINFO_MIME_TYPE);
header('Content-Type: '.finfo_file($finfo, $path));

$finfo = finfo_open(FILEINFO_MIME_ENCODING);
header('Content-Transfer-Encoding: '.finfo_file($finfo, $path)); 

header('Content-disposition: attachment; filename="'.basename($path).'"'); 
readfile($path); // do the double-download-dance (dirty but worky)

4

Kode berikut adalah cara yang benar untuk mengimplementasikan layanan unduhan di php seperti yang dijelaskan dalam tutorial berikut

header('Content-Type: application/zip');
header("Content-Disposition: attachment; filename=\"$file_name\"");
set_time_limit(0);
$file = @fopen($filePath, "rb");
while(!feof($file)) {
    print(@fread($file, 1024*8));
    ob_flush();
    flush();
}

1
Anda memiliki dua variabel dalam kode ini: file_namedan filePath. Praktik pengkodean yang tidak terlalu baik. Apalagi tanpa penjelasan. Menautkan ke tutorial eksternal tidak membantu.
Khom Nazid

2

coba ini:

header('Content-type: audio/mp3'); 
header('Content-disposition: attachment; 
filename=“'.$trackname'”');                             
readfile('folder name /'.$trackname);          
exit();


1

Anda juga dapat melakukan streaming unduhan yang akan menghabiskan lebih sedikit sumber daya. contoh:

$readableStream = fopen('test.zip', 'rb');
$writableStream = fopen('php://output', 'wb');

header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="test.zip"');
stream_copy_to_stream($readableStream, $writableStream);
ob_flush();
flush();

Dalam contoh di atas, saya mengunduh test.zip (yang sebenarnya adalah zip studio android di mesin lokal saya). php: // output adalah aliran hanya-tulis (umumnya digunakan oleh echo atau print). setelah itu, Anda hanya perlu menyetel header yang diperlukan dan memanggil stream_copy_to_stream (sumber, tujuan). metode stream_copy_to_stream () bertindak sebagai pipa yang mengambil input dari aliran sumber (aliran baca) dan menyalurkannya ke aliran tujuan (aliran tulis) dan juga menghindari masalah kehabisan memori yang diizinkan sehingga Anda benar-benar dapat mengunduh file yang lebih besar daripada PHP Anda memory_limit.


Apa yang Anda maksud dengan unduhan itu streaming?
Parsa Yazdani

1
@ParsaYazdani Artinya data yang diunduh akan dipotong-potong. Silakan lihat konsep streaming untuk lebih jelasnya. Catatan: ini bukan satu-satunya untuk melakukan streaming (potongan) mengunduh file dalam PHP. Tapi itu pasti salah satu metode termudah.
Saud Qureshi

0

Jawaban di atas saya berhasil. Tapi, saya ingin menyumbangkan metode tentang bagaimana melakukannya menggunakan GET

di halaman html / php Anda

$File = 'some/dir/file.jpg';
<a href="<?php echo '../sumdir/download.php?f='.$File; ?>" target="_blank">Download</a>

dan download.phpberisi

$file = $_GET['f']; 

header("Expires: 0");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");

$ext = pathinfo($file, PATHINFO_EXTENSION);
$basename = pathinfo($file, PATHINFO_BASENAME);

header("Content-type: application/".$ext);
header('Content-length: '.filesize($file));
header("Content-Disposition: attachment; filename=\"$basename\"");
ob_clean(); 
flush();
readfile($file);
exit;

ini harus bekerja pada semua jenis file. ini tidak diuji menggunakan POST, tetapi dapat berhasil.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.