php -- PHP實現點擊a標簽的href做鏈接時,直接保存文件(任何類型),而不是通過瀏覽器直接打開下載的文件


之前做項目遇到這樣一個問題,就是在php環境下,用a標簽的href鏈接到一個資源,比如是mp3或者lrc文件時,點擊之后不是出現保存文件的提示,而是調用本地程序打開文件或者直接在瀏覽器上解析。網上說可以全部做成rar格式的文件,這個一方面不方便,有些情況下也不可能完全這樣做,還有實際上,做過測試會發現,在content-type:text/html的情況下,即時是rar有時也會被瀏覽器直接解析,無法實現下載的功能,那這個問題是不是就無解了呢?答案是否定的,幾番搜索+測試,終於發現了一個可行的解決方案,就是在點擊a標簽的鏈接之后,不是直接請求資源,而是對header做一下預處理,再去readfile就可以了。下面附上相關的測試代碼:

一、

index.php中:

<?php 
    echo "<a href='process.php?filename=halo.mp3'>下載</a>"
?>

process.php中:

<?php 
    header("Content-type: application/octet-stream");

    header('Content-Disposition: attachment; filename="'. basename($_GET['filename']).'"');

    header("Content-Length: ". filesize($_GET['filename']));

    readfile($_GET['filename']);
?>

這是最簡單的方法,但是有個問題:如果請求的路徑中包含中文,那么下載的文件名有可能就是亂碼。

 

二、

針對上面問題的解決方案,

index.php中:

<?php 
    echo "<a href='process.php?filename=halo光環.mp3'>下載</a>"
?>

process.php中:

<?php
    header("Content-type: application/octet-stream");

    //處理中文文件名

    $ua = $_SERVER["HTTP_USER_AGENT"];

    $encoded_filename = urlencode($_GET['filename']);

    $encoded_filename = str_replace("+", "%20", $encoded_filename);

    if (preg_match("/MSIE/", $ua)) {

    header('Content-Disposition: attachment; filename="' . $encoded_filename . '"');

    } else if (preg_match("/Firefox/", $ua)) {

    header("Content-Disposition: attachment; filename*=\"utf8''" . $_GET['filename'] . '"');

    } else {

    header('Content-Disposition: attachment; filename="' . $_GET['filename'] . '"');

    }

    header("Content-Length: ". filesize($_GET['filename']));

    readfile($_GET['filename']);
?>

輸出的時候,如果是Apache+PHP,那么還需要發送到Apache的輸出緩沖區,最后才發送給用戶。而對於Nginx+fpm,如果它們分開部署的話,那還會帶來額外的網絡IO。

 

三、

現在貌似沒有問題了,但是readfile還是有問題的,雖然PHP的readfile嘗試實現的盡量高效,不占用PHP本身的內存,但是實際上它還是需要采用MMAP(如果支持),或者是一個固定的buffer去循環讀取文件,直接輸出。

那么能不能繞過PHP這層呢,直接由webserver把文件發送給用戶呢?可以的,我們可以使用Apache的module mode_xsendfile,讓Apache直接發送這個文件給用戶。

代碼實現如下:(process.php)

header("Content-type: application/octet-stream");

//處理中文文件名

$ua = $_SERVER["HTTP_USER_AGENT"];

$encoded_filename = urlencode($_GET['filename']);

$encoded_filename = str_replace("+", "%20", $encoded_filename);

if (preg_match("/MSIE/", $ua)) {

header('Content-Disposition: attachment; filename="' . $encoded_filename . '"');

} else if (preg_match("/Firefox/", $ua)) {

header("Content-Disposition: attachment; filename*=\"utf8''" . $_GET['filename'] . '"');

} else {

header('Content-Disposition: attachment; filename="' . $_GET['filename'] . '"');

}

//讓Xsendfile發送文件
  header("X-Sendfile: $_GET['filename']"); 

 

最后,如果願意的話,可以先判斷后綴,因為有時候圖片當成文件下載也會引起一些不方便的:

 $type = strrchr($_GET['filename'], "."); //獲取后綴 
       if($type == "jpg" || "png" || "gif"){ 
       header("Content-Disposition: filename=$_GET['filename']"); //這里我試過,加引號的話,下載時會加到文件名中 
       header("Content-Type: image/$type"); 
       }

 

 

轉自:http://m.blog.csdn.net/blog/nkliming/8536311


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM