[CodeIgniter] 解決 CI 下載函式 force_download 碰到 IE 下載中文檔名變亂碼

要讓瀏覽器強制下載某個檔案,而不是直接開啟在瀏覽器裡面,絕大部分的做法應該都是用HTTP Header送出Content-Disposition,將它設定為attachment,並指定一個檔名,那麼瀏覽器就會將HTTP Body裡面的二進位資料做為檔案內容,開啟下載對話框,以所指定的檔名,讓使用者下載檔案。


以PHP為例,簡單的寫法大概是像這樣:

以前當我寫到檔案下載的這類功能時,常常記不住這堆header的寫法,直到我的膝蓋中了一箭…不,直到我遇見了CodeIgniter…

CodeIgniter有個很好用的helper函式叫force_download,幫我們把這些落落長的header都寫好好了,只要把它load進來,然後這樣給它用下去,剩下的事情它都幫你搞定:

是不是很簡單呢? 於是我就很快樂的將它用到我最近的一個案子上,直到我的膝蓋又中了一箭…不,直到我用IE來測試的時候,發現當我檔名用中文的時候,IE跳出來的下載對話框上面的檔名竟然變成了亂碼,像這樣…

唉唷~~這怎麼可以呢,人家火狐和窟窿明明都沒問題的呀。經過咕狗大人的指點,原來這算是IE的一個Bug,IE對於Content-Disposition是用ANSI編碼,碰到你用Unicode編碼的檔名就爆炸了。而偏偏CI是阿凸啊寫的,人家下載檔案才不會用到中文檔名咧,所以force_download就沒有處理到中文檔名碰到IE的問題了。

解決辦法

所以該怎麼解決呢,有三種辦法

1. 叫user去改IE的設定
到[工具]->[網際網路選項]->[進階],找到 [傳送UTF-8 URL] 那個給它打勾
但是我們做網站的,面對的user百百款,怎麼可能叫他們自己去改IE的設定呢,這實在很夭壽,所以只好我們這邊自己動…

2. 改force_download這個函式
修改system/helpers/download_helper.php這支程式,找到最後面送出header的那一段,把Content-Disposition後面的filename用iconv把檔名改編碼成Big5,像這樣:

不過這會動到CI的系統核心,我個人不是很喜歡,因為如果你下次CI做更新的時候,肯定會忘了再來這裡改一遍,到時候又會爆炸了…

3. 修改你的controller程式
這是比較好的方法,在你自己的controller裡面就把檔名轉成Big5再帶進去,就不需要動到核心啦

最後還是那句老話,IE加油,好嗎?

參考
ASP.NET 如何設定強制下載檔案並正確處理中文檔名的問題
[CodeIgniter] 解決 CI 下載函數 force_download 在 IE 底下檔案標題亂碼
[CodeIgniter] 解決 CI 下載函數 force_download 使用 IE 下載時檔名亂碼

延伸閱讀
“直到我的膝蓋中了一箭”的由來

發佈留言