Làm cách nào để mã hóa tham số tên tệp của tiêu đề Xử lý nội dung trong HTTP?


535

Các ứng dụng web muốn buộc tài nguyên được tải xuống thay vì được hiển thị trực tiếp trong trình duyệt Web sẽ đưa ra một Content-Dispositiontiêu đề trong phản hồi HTTP của biểu mẫu:

Content-Disposition: attachment; filename=FILENAME

Các filenametham số có thể được sử dụng để đề nghị một tên cho tập tin vào đó tài nguyên được tải bởi trình duyệt. Tuy nhiên, RFC 2183 (Bố trí nội dung) nêu trong phần 2.3 (Tham số tên tệp) rằng tên tệp chỉ có thể sử dụng các ký tự US-ASCII:

Ngữ pháp [RFC 2045] hiện tại giới hạn các giá trị tham số (và do đó tên tệp xử lý nội dung) đối với US-ASCII. Chúng tôi nhận thấy sự mong muốn lớn khi cho phép các bộ ký tự tùy ý trong tên tệp, nhưng vượt quá phạm vi của tài liệu này để xác định các cơ chế cần thiết.

Tuy nhiên, có bằng chứng thực nghiệm rằng hầu hết các trình duyệt Web phổ biến hiện nay dường như cho phép các ký tự không phải là US-ASCII (vì không có tiêu chuẩn) không đồng ý về sơ đồ mã hóa và đặc tả bộ ký tự của tên tệp. Khi đó, câu hỏi đặt ra là các lược đồ và mã hóa khác nhau được sử dụng bởi các trình duyệt phổ biến là gì nếu tên tệp có tên là na naveveileile (không có dấu ngoặc kép và chữ cái thứ ba là U + 00EF) cần được mã hóa vào tiêu đề Xử lý nội dung?

Đối với mục đích của câu hỏi này, các trình duyệt phổ biến là:

  • Firefox
  • trình duyệt web IE
  • Safari
  • Google Chrome
  • Opera

Nó đã hoạt động cho Mobile Safari (utf-8 thô theo đề xuất của @Martin Ørding-Thomsen), nhưng điều đó không hoạt động với GoodReader từ cùng một thiết bị. Có ý kiến ​​gì không?
Thilo


1
Câu trả lời của Kornel đã chứng minh là con đường ít kháng cự nhất, nếu bạn có thể đặt đoạn cuối của con đường; cặp này với Content-Disposition: attachment.
Antti Haapala

Câu trả lời:


94

Có thảo luận về vấn đề này, bao gồm các liên kết đến kiểm tra trình duyệt và khả năng tương thích ngược, trong RFC 5987 được đề xuất , "Bộ ký tự và mã hóa ngôn ngữ cho các tham số trường tiêu đề giao thức truyền siêu văn bản (HTTP)."

RFC 2183 chỉ ra rằng các tiêu đề như vậy nên được mã hóa theo RFC 2184 , đã bị RFC 2231 lỗi thời , được bao phủ bởi dự thảo RFC ở trên.


5
Cũng lưu ý rằng bản nháp internet (không phải "bản nháp RFC") đã được hoàn thành và tài liệu cuối cùng là RFC 5987 ( greenbytes.de/tech/webdav/rfc5987.html )
Julian Reschke

11
Liên quan đến điều này, tôi phát hiện ra rằng Firefox (phiên bản 4-9 bao gồm) phá vỡ nếu có một dấu phẩy (,) trong tên tập tin, ví dụ Content-Disposition: filename="foo, bar.pdf". Kết quả là firefox tải tệp chính xác nhưng vẫn giữ .partphần mở rộng (ví dụ foo,bar.pdf-1.part). Sau đó, tất nhiên tệp sẽ không mở đúng vì ứng dụng không được liên kết .part. Các ký tự ASCII khác dường như hoạt động tốt.
Catchdave

3
Để biết thêm về hành vi của IE, hãy xem blogs.msdn.com/b/ieinternals/archive/2010/06/07/...
EricLaw

5
@catchdave: Bạn đã quên "tệp đính kèm;" phần.
Christoffer Hammarström

6
Nói chung, đây không là gì ngoài câu trả lời chỉ liên kết với 74 lượt upvote.
Antti Haapala

364

Tôi biết đây là một bài viết cũ nhưng nó vẫn rất liên quan. Tôi đã thấy rằng các trình duyệt hiện đại hỗ trợ rfc5987, cho phép mã hóa utf-8, phần trăm được mã hóa (mã hóa url). Sau đó, tập tin Naïve trở thành:

Content-Disposition: attachment; filename*=UTF-8''Na%C3%AFve%20file.txt

Safari (5) không hỗ trợ này. Thay vào đó, bạn nên sử dụng tiêu chuẩn Safari để viết tên tệp trực tiếp trong tiêu đề được mã hóa utf-8 của bạn:

Content-Disposition: attachment; filename=Naïve file.txt

IE8 trở lên cũng không hỗ trợ nó và bạn cần sử dụng tiêu chuẩn IE của mã hóa utf-8, phần trăm được mã hóa:

Content-Disposition: attachment; filename=Na%C3%AFve%20file.txt

Trong ASP.Net tôi sử dụng mã sau:

string contentDisposition;
if (Request.Browser.Browser == "IE" && (Request.Browser.Version == "7.0" || Request.Browser.Version == "8.0"))
    contentDisposition = "attachment; filename=" + Uri.EscapeDataString(fileName);
else if (Request.Browser.Browser == "Safari")
    contentDisposition = "attachment; filename=" + fileName;
else
    contentDisposition = "attachment; filename*=UTF-8''" + Uri.EscapeDataString(fileName);
Response.AddHeader("Content-Disposition", contentDisposition);

Tôi đã thử nghiệm ở trên bằng IE7, IE8, IE9, Chrome 13, Opera 11, FF5, Safari 5.

Cập nhật tháng 11 năm 2013:

Đây là mã tôi hiện đang sử dụng. Tôi vẫn phải hỗ trợ IE8, vì vậy tôi không thể thoát khỏi phần đầu tiên. Hóa ra các trình duyệt trên Android sử dụng trình quản lý tải xuống được tích hợp trong Android và nó không thể phân tích cú pháp tên tệp theo cách tiêu chuẩn.

string contentDisposition;
if (Request.Browser.Browser == "IE" && (Request.Browser.Version == "7.0" || Request.Browser.Version == "8.0"))
    contentDisposition = "attachment; filename=" + Uri.EscapeDataString(fileName);
else if (Request.UserAgent != null && Request.UserAgent.ToLowerInvariant().Contains("android")) // android built-in download manager (all browsers on android)
    contentDisposition = "attachment; filename=\"" + MakeAndroidSafeFileName(fileName) + "\"";
else
    contentDisposition = "attachment; filename=\"" + fileName + "\"; filename*=UTF-8''" + Uri.EscapeDataString(fileName);
Response.AddHeader("Content-Disposition", contentDisposition);

Hiện tại đã được thử nghiệm trong IE7-11, Chrome 32, Opera 12, FF25, Safari 6, sử dụng tên tệp này để tải xuống: 你好 abcABCæøåÆØÅäöüïëêîâéíáóúýñ½ §! # ¤% & () = `@ £ $ € [[] ^ ~ '-_ ,; txt

Trên IE7 nó hoạt động cho một số ký tự nhưng không phải tất cả. Nhưng ai quan tâm đến IE7 ngày nay?

Đây là chức năng tôi sử dụng để tạo tên tệp an toàn cho Android. Lưu ý rằng tôi không biết những ký tự nào được hỗ trợ trên Android nhưng tôi đã kiểm tra xem những ký tự này có hoạt động không:

private static readonly Dictionary<char, char> AndroidAllowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ._-+,@£$€!½§~'=()[]{}0123456789".ToDictionary(c => c);
private string MakeAndroidSafeFileName(string fileName)
{
    char[] newFileName = fileName.ToCharArray();
    for (int i = 0; i < newFileName.Length; i++)
    {
        if (!AndroidAllowedChars.ContainsKey(newFileName[i]))
            newFileName[i] = '_';
    }
    return new string(newFileName);
}

@TomZ: Tôi đã thử nghiệm trong IE7 và IE8 và hóa ra tôi không cần phải thoát dấu nháy đơn ('). Bạn có một ví dụ mà nó thất bại?

@Dave Van den Eynde: Kết hợp hai tên tệp trên một dòng theo RFC6266 hoạt động ngoại trừ Android và IE7 + 8 và tôi đã cập nhật mã để phản ánh điều này. Cảm ơn vì đã góp ý.

@Thilo: Không có ý tưởng về GoodReader hoặc bất kỳ trình duyệt không phải trình duyệt nào khác. Bạn có thể có một số may mắn khi sử dụng phương pháp Android.

@Alex Zhukovskiy: Tôi không biết tại sao nhưng như đã thảo luận trên Connect, nó dường như không hoạt động tốt lắm.


1
Đã nhận nó làm việc cho Mobile Safari (nguyên utf-8 như đề xuất ở trên), nhưng điều đó không làm việc cho GoodReader từ cùng một thiết bị. Có ý kiến ​​gì không?
Thilo

1
IE7 và 8 cũng cần các dấu nháy đơn được thoát: .Replace ("'", Uri.HexEscape (' \ ''))
TomZ

1
Viết trực tiếp các ký tự UTF-8 dường như hoạt động cho các phiên bản hiện tại của Firefox, Chrome và Opera. Không kiểm tra Safari & IE.
Martin Tournoij

20
Tại sao không kết hợp chúng, như Content-Disposition: attachment; filename*=UTF-8''Na%C3%AFve%20file.txt; filename=Na%C3%AFve%20file.txtvà bỏ qua trình duyệt đánh hơi? Liệu điều đó có hiệu quả?
Dave Van den Eynde

9
Những người tốt bụng tại fastmail đã tìm thấy một cách giải quyết khác: blog.fastmail.com/2011/06/24/doad-non-english-filenames Nội dung-Bố trí: tệp đính kèm; tên tệp = "foo-% c3% a4.html"; tên tệp * = UTF-8''foo-% c3% a4.html Chỉ định tên tệp hai lần (một lần không có tiền tố UTF-8 và một lần với) làm cho nó hoạt động trong IE8-11, Edge, Chrome, Firefox và Safari ( có vẻ như táo cố định safari, vì vậy nó cũng hoạt động ở đó)
wullinkm

169

Có một cách thay thế đơn giản và rất mạnh mẽ: sử dụng URL chứa tên tệp bạn muốn .

Khi tên sau dấu gạch chéo cuối cùng là tên bạn muốn, bạn không cần thêm bất kỳ tiêu đề nào!

Thủ thuật này hoạt động:

/real_script.php/fake_filename.doc

Và nếu máy chủ của bạn hỗ trợ viết lại URL (ví dụ như mod_rewritetrong Apache) thì bạn hoàn toàn có thể ẩn phần tập lệnh.

Ký tự trong URL phải ở trong UTF-8, urlencoded byte-by-byte:

/mot%C3%B6rhead   # motörhead

3
? Hãy thử GetAttachment.aspx / fake_filename.doc id = 34 (mặc dù nó có thể là Apache chỉ những đứa)
Kornel

2
đây là một giải pháp tuyệt vời; thực sự đã giúp tôi rất nhiều. cảm ơn.
kristopolous

6
Tôi đã đi xuống con đường mòn thỏ và thử một số giải pháp khác; cố gắng phát hiện ra trình duyệt và phiên bản chính xác để đặt tiêu đề chính xác là quá nhiều ác mộng. Chrome đã xác định không chính xác là Safari hoàn toàn không hoạt động giống nhau (phá vỡ dấu phẩy nếu không được mã hóa chính xác). Hãy tự giải quyết rắc rối, sử dụng giải pháp này và đặt bí danh URL khi cần.
mpen

3
Các /:id/:filenamephương pháp thực sự đơn giản và các công trình, cảm ơn bạn!
Luca Steeb

2
Một ngàn lần "Có". Bạn sẽ nghiêm túc giành được thời gian với điều này. Thậm chí nhiều hơn - một số trình duyệt Android sẽ ra khỏi căn hộ bỏ qua các Content-Dispositionvà tạo tên tập tin rất thú vị thay vì (họ sẽ được tạo ra từ đường dẫn của bạn). Vì vậy, giải pháp duy nhất để giữ sự tỉnh táo của một người chỉ là thiết lập Content-Disposition: attachmentvà chuyển tên tệp mong muốn làm thành phần đường dẫn cuối cùng:
Julik

73

RFC 6266 mô tả việc sử dụng của trường Tiêu đề xử lý nội dung trong Giao thức truyền siêu văn bản (HTTP) . Trích dẫn từ đó:

6. Cân nhắc quốc tế hóa

Các “ filename*” tham số ( Phần 4.3 ), sử dụng mã hóa định nghĩa trong [ RFC5987 ], cho phép các máy chủ để nhân vật truyền bên ngoài bộ ký tự ISO-8859-1, và cũng để tùy chọn định ngôn ngữ được sử dụng.

Và trong phần ví dụ của họ :

Ví dụ này giống như ở trên, nhưng thêm tham số "tên tệp" để tương thích với các tác nhân người dùng không triển khai RFC 5987 :

Content-Disposition: attachment;
                     filename="EURO rates";
                     filename*=utf-8''%e2%82%ac%20rates

Lưu ý: Những tác nhân người dùng không hỗ trợ mã hóa RFC 5987 bỏ qua phạm vi phạm lỗi filename*khi nó xảy ra sau khi phạm lỗi filename.

Trong Phụ lục D cũng có một danh sách dài các đề xuất để tăng khả năng tương tác. Nó cũng chỉ ra một trang web so sánh việc thực hiện . Các thử nghiệm tất cả hiện tại phù hợp với tên tệp phổ biến bao gồm:

  • attwithisofnplain : tên tệp ISO-8859-1 đơn giản với dấu ngoặc kép và không có mã hóa. Điều này đòi hỏi một tên tệp là tất cả ISO-8859-1 và không chứa dấu phần trăm, ít nhất là không ở phía trước các chữ số hex.
  • attfnboth : hai tham số theo thứ tự được mô tả ở trên. Nên hoạt động đối với hầu hết các tên tệp trên hầu hết các trình duyệt, mặc dù IE8 sẽ sử dụng filenametham số bản lề.

Đó RFC 5987 trong tài liệu tham khảo lần lượt RFC 2231 , trong đó mô tả các định dạng thực tế. 2231 là chủ yếu cho mail, và 5987 cho chúng ta biết những phần nào có thể được sử dụng cho tiêu đề HTTP là tốt. Đừng nhầm lẫn điều này với các tiêu đề MIME được sử dụng bên trong phần thânmultipart/form-data HTTP , được điều chỉnh bởi RFC 2388 ( đặc biệt là phần 4.4 ) và bản nháp HTML 5 .


1
Tôi gặp sự cố trong Safari. Khi tải xuống các tệp có tên tiếng Nga đã nhận được các ký tự sai và không thể đọc được. Các giải pháp đã giúp. Nhưng chúng ta cần gửi một tiêu đề trong một hàng duy nhất (!!!).
evtuhovdo

16

Tài liệu sau đây được liên kết từ dự thảo RFC được Jim đề cập trong câu trả lời của ông tiếp tục giải quyết câu hỏi và chắc chắn đáng ghi chú trực tiếp tại đây:

Các trường hợp thử nghiệm cho tiêu đề xử lý nội dung HTTP và mã hóa RFC 2231/2047


Lưu ý rằng người ta có thể cung cấp cả hai cách mã hóa tham số tên tệp và chúng có vẻ hoạt động chính xác với các trình duyệt cũ và trình duyệt mới (cũ là MSIE8 và Safari trong trường hợp này). Kiểm tra attfnboth trong báo cáo được đề cập bởi @AtifAziz.
Pablo Montilla

11

trong asp.net mvc2 tôi sử dụng một cái gì đó như thế này:

return File(
    tempFile
    , "application/octet-stream"
    , HttpUtility.UrlPathEncode(fileName)
    );

Tôi đoán nếu bạn không sử dụng mvc (2), bạn có thể mã hóa tên tệp bằng cách sử dụng

HttpUtility.UrlPathEncode(fileName)

2
Mã hóa Url để mã hóa tên tệp không hợp lệ, các trình duyệt phải giải mã url.
SerialSeb

IE 11 chắc chắn không giải mã được mã hóa url trong lĩnh vực này.
giả mã

Nhưng nó cần phải được mã hóa khi trình duyệt là Chrome hoặc IE, các trình duyệt khác như FF, Safari và Opera hoạt động tốt với mã hóa ngoài
Reza

11

Đặt tên tập tin trong dấu ngoặc kép. Giải quyết vấn đề cho tôi. Như thế này:

Content-Disposition: attachment; filename="My Report.doc"

http://kb.mozillazine.org/Filenames_with_spaces_are_truncated_upon_d Download

Tôi đã thử nghiệm nhiều lựa chọn. Trình duyệt không hỗ trợ thông số kỹ thuật và hành động khác nhau, tôi tin rằng dấu ngoặc kép là lựa chọn tốt nhất.


3
Điều đáng buồn này không giải quyết tất cả các vấn đề được giải thích trong các câu trả lời ở trên.
Luca Steeb

2
Điều này sẽ cho phép bạn quay trở lại một tên tập tin với không gian, &, %, #vv Vì vậy, nó giải quyết đó.
Don Cheadle

Điều gì sẽ xảy ra nếu tên tệp chứa dấu ngoặc kép (có, điều này có thể xảy ra), Như được chỉ định trong RFC 6266, tên tệp là "chuỗi trích dẫn" và như được chỉ định trong RFC 2616, dấu ngoặc kép trong chuỗi trích dẫn phải được thoát bằng dấu gạch chéo ngược.
Barshe Roussy

10

Tôi sử dụng các đoạn mã sau để mã hóa (giả sử fileName chứa tên tệp và phần mở rộng của tệp, tức là: test.txt):


PHP:

if ( strpos ( $_SERVER [ 'HTTP_USER_AGENT' ], "MSIE" ) > 0 )
{
     header ( 'Content-Disposition: attachment; filename="' . rawurlencode ( $fileName ) . '"' );
}
else
{
     header( 'Content-Disposition: attachment; filename*=UTF-8\'\'' . rawurlencode ( $fileName ) );
}

Java:

fileName = request.getHeader ( "user-agent" ).contains ( "MSIE" ) ? URLEncoder.encode ( fileName, "utf-8") : MimeUtility.encodeWord ( fileName );
response.setHeader ( "Content-disposition", "attachment; filename=\"" + fileName + "\"");

Đúng, nó phải có rawurlencodetrong PHP ít nhất là cho filename*=tiêu đề sắp xếp kể từ khi value-charsđược sử dụng trong ext-valueRFC 6266-> RFC 5987 (xem tools.ietf.org/html/rfc6266#section-4.1 & tools.ietf.org/html/rfc5987#section -3.2.1 ) không cho phép không gian mà không thoát phần trăm ( filename=mặt khác, dường như nó có thể cho phép một không gian mà không thoát ra ngoài mặc dù chỉ có ASCII nên có mặt ở đây). Không cần phải mã hóa với sự nghiêm ngặt hoàn toàn của rawurlencode, vì vậy một vài ký tự có thể không được giải mã: gist.github.com/brettz9/8752120
Brett Zamir

9

Trong ASP.NET Web API, tôi url mã hóa tên tệp:

public static class HttpRequestMessageExtensions
{
    public static HttpResponseMessage CreateFileResponse(this HttpRequestMessage request, byte[] data, string filename, string mediaType)
    {
        HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
        var stream = new MemoryStream(data);
        stream.Position = 0;

        response.Content = new StreamContent(stream);

        response.Content.Headers.ContentType = 
            new MediaTypeHeaderValue(mediaType);

        // URL-Encode filename
        // Fixes behavior in IE, that filenames with non US-ASCII characters
        // stay correct (not "_utf-8_.......=_=").
        var encodedFilename = HttpUtility.UrlEncode(filename, Encoding.UTF8);

        response.Content.Headers.ContentDisposition =
            new ContentDispositionHeaderValue("attachment") { FileName = encodedFilename };
        return response;
    }
}

IE 9 Không cố định
IE 9 Cố định


5

Tôi đã thử nghiệm mã sau đây trong tất cả các trình duyệt chính, bao gồm cả Explorers cũ (thông qua chế độ tương thích) và nó hoạt động tốt ở mọi nơi:

$filename = $_GET['file']; //this string from $_GET is already decoded
if (strstr($_SERVER['HTTP_USER_AGENT'],"MSIE"))
  $filename = rawurlencode($filename);
header('Content-Disposition: attachment; filename="'.$filename.'"');

5

Tôi đã kết thúc với đoạn mã sau trong tập lệnh "download.php" của mình (dựa trên blogpost nàycác trường hợp thử nghiệm này ).

$il1_filename = utf8_decode($filename);
$to_underscore = "\"\\#*;:|<>/?";
$safe_filename = strtr($il1_filename, $to_underscore, str_repeat("_", strlen($to_underscore)));

header("Content-Disposition: attachment; filename=\"$safe_filename\""
.( $safe_filename === $filename ? "" : "; filename*=UTF-8''".rawurlencode($filename) ));

Điều này sử dụng cách tiêu chuẩn của filename = "..." miễn là chỉ có các ký tự iso-latin1 và "an toàn" được sử dụng; nếu không, nó sẽ thêm tên tệp * = UTF-8 '' cách mã hóa url. Theo trường hợp thử nghiệm cụ thể này , nó sẽ hoạt động từ MSIE9 trở lên và trên FF, Chrome, Safari gần đây; trên phiên bản MSIE thấp hơn, nó sẽ cung cấp tên tệp chứa phiên bản ISO8859-1 của tên tệp, với dấu gạch dưới trên các ký tự không có trong mã hóa này.

Lưu ý cuối cùng: tối đa. kích thước cho mỗi trường tiêu đề là 8190 byte trên apache. UTF-8 có thể lên tới bốn byte cho mỗi ký tự; sau rawurlencode, nó là x3 = 12 byte cho mỗi ký tự. Khá kém hiệu quả, nhưng về mặt lý thuyết vẫn có thể có hơn 600 "nụ cười"% F0% 9F% 98% 81 trong tên tệp.


... nhưng độ dài tên tệp có thể chuyển tối đa cũng phụ thuộc vào máy khách. Chỉ cần phát hiện ra rằng nhiều nhất [89 nụ cười😁] .pdf tên tệp được thông qua MSIE11. Trong Firefox37, tối đa là [111x] .pdf. Chrome41 cắt ngắn tên tệp ở nụ cười thứ 110. Thật thú vị, hậu tố được chuyển ok.
apurkrt

5

Nếu bạn đang sử dụng một phụ trợ của nodejs, bạn có thể sử dụng đoạn mã sau tôi tìm thấy ở đây

var fileName = 'my file(2).txt';
var header = "Content-Disposition: attachment; filename*=UTF-8''" 
             + encodeRFC5987ValueChars(fileName);

function encodeRFC5987ValueChars (str) {
    return encodeURIComponent(str).
        // Note that although RFC3986 reserves "!", RFC5987 does not,
        // so we do not need to escape it
        replace(/['()]/g, escape). // i.e., %27 %28 %29
        replace(/\*/g, '%2A').
            // The following are not required for percent-encoding per RFC5987, 
            // so we can allow for a little better readability over the wire: |`^
            replace(/%(?:7C|60|5E)/g, unescape);
}

1
Tốt hơn để sử dụng encodeURI(str). Ví dụ với ngày trong tên tệp: encodeURIComponent('"Kornél Kovács 1/1/2016')=> "Kornél Kovács 1% 2F1% 2F2016" so với encodeURI('"Kornél Kovács 1/1/2016')=> "Kornél Kovács 1/1/2016"
gdibble

4

Trong PHP, điều này đã làm điều đó cho tôi (giả sử tên tệp được mã hóa UTF8):

header('Content-Disposition: attachment;'
    . 'filename="' . addslashes(utf8_decode($filename)) . '";'
    . 'filename*=utf-8\'\'' . rawurlencode($filename));

Đã thử nghiệm với IE8-11, Firefox và Chrome.
Nếu trình duyệt có thể giải thích tên tệp * = utf-8, nó sẽ sử dụng phiên bản UTF8 của tên tệp, nếu không, nó sẽ sử dụng tên tệp được giải mã. Nếu tên tệp của bạn chứa các ký tự không thể được biểu thị trong ISO-8859-1, bạn có thể muốn xem xét sử dụng iconvthay thế.


3
Mặc dù mã này có thể trả lời câu hỏi, cung cấp ngữ cảnh bổ sung về lý do tại sao và / hoặc cách nó trả lời câu hỏi sẽ cải thiện đáng kể giá trị lâu dài của nó. Vui lòng chỉnh sửa câu trả lời của bạn để thêm một số lời giải thích.
Toby Speight

2
Whoa, không có câu trả lời nào chỉ có mã ở trên bị hạ cấp hoặc phê bình như thế. Ngoài ra, tôi đã tìm thấy lý do tại sao đã được trả lời đủ rõ: IE không giải thích tên tệp * = utf-8 nhưng cần phiên bản ISO8859-1 của tên tệp mà tập lệnh này cung cấp. Chỉ muốn cung cấp cho người lười biếng một mã đơn giản làm việc cho PHP.
Gustav

Tôi nghĩ rằng điều này đã bị hạ thấp bởi vì câu hỏi không phải là ngôn ngữ cụ thể mà là về những gì RFC sẽ bám vào khi thực hiện mã hóa tiêu đề. Tuy nhiên, cảm ơn vì câu trả lời này, cho PHP, mã này đã làm cho tai ương của tôi biến mất.
j4k3

Cảm ơn bạn. Câu trả lời này có thể không trả lời đúng câu hỏi, nhưng đó chính xác là những gì tôi đang tìm kiếm và giúp tôi giải quyết vấn đề trong Python.
Lyndsy Simon

1
Tôi khá chắc chắn rằng mã này có thể được sử dụng như một vector tấn công nếu người dùng có thể kiểm soát tên của tệp.
Antti Haapala

3

Chỉ là một bản cập nhật vì tôi đã thử tất cả những thứ này ngày hôm nay để đáp ứng với vấn đề của khách hàng

  • Ngoại trừ Safari được định cấu hình cho tiếng Nhật, tất cả các trình duyệt mà khách hàng của chúng tôi đã kiểm tra hoạt động tốt nhất với filename = text.pdf - trong đó văn bản là giá trị khách hàng được tuần tự hóa bởi ASP.Net/IIS trong utf-8 mà không cần mã hóa url. Vì một số lý do, Safari được định cấu hình cho tiếng Anh sẽ chấp nhận và lưu đúng tệp có tên tiếng Nhật utf-8 nhưng cùng một trình duyệt được định cấu hình cho tiếng Nhật sẽ lưu tệp với ký tự utf-8 không bị giải thích. Tất cả các trình duyệt khác được thử nghiệm dường như hoạt động tốt nhất / tốt (bất kể cấu hình ngôn ngữ) với tên tệp utf-8 được mã hóa mà không cần mã hóa url.
  • Tôi không thể tìm thấy một trình duyệt duy nhất thực hiện Rfc5987 / 8187 tại tất cả . Tôi đã thử nghiệm với các bản Chrome, Firefox mới nhất cộng với IE 11 và Edge. Tôi đã thử đặt tiêu đề chỉ bằng tên tệp * = utf-8''texturlencoding.pdf, đặt tiêu đề bằng cả tên tệp = text.pdf; tên tệp * = utf-8''texturlencoding.pdf. Không một tính năng nào của Rfc5987 / 8187 dường như được xử lý chính xác trong bất kỳ điều nào ở trên.

Đây là một bản cập nhật tốt. Bạn có thể giải thích các bài kiểm tra cụ thể mà bạn đã thử không?
Brad

3

Khung công tác PHP Symfony 4 có $filenameFallbacktrong HeaderUtils::makeDisposition. Bạn có thể xem xét chức năng này để biết chi tiết - nó tương tự như các câu trả lời ở trên.

Ví dụ sử dụng:

$filenameFallback = preg_replace('#^.*\.#', md5($filename) . '.', $filename);
$disposition = $response->headers->makeDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, $filename, $filenameFallback);
$response->headers->set('Content-Disposition', $disposition);

1

Giải pháp cổ điển

Hầu hết các trình duyệt hiện đại đều hỗ trợ vượt qua Filenamenhư UTF-8hiện tại nhưng như trường hợp với giải pháp Tải lên tệp mà tôi sử dụng dựa trên FreeASPUpload.Net (trang web không còn tồn tại, liên kết các điểm đến archive.org ) nó sẽ không hoạt động như phân tích cú pháp của nhị phân dựa vào việc đọc các chuỗi được mã hóa ASCII byte đơn, hoạt động tốt khi bạn truyền dữ liệu được mã hóa UTF-8 cho đến khi bạn nhận được các ký tự ASCII không hỗ trợ.

Tuy nhiên tôi đã có thể tìm một giải pháp để lấy mã để đọc và phân tích nhị phân là UTF-8.

Public Function BytesToString(bytes)    'UTF-8..
  Dim bslen
  Dim i, k , N 
  Dim b , count 
  Dim str

  bslen = LenB(bytes)
  str=""

  i = 0
  Do While i < bslen
    b = AscB(MidB(bytes,i+1,1))

    If (b And &HFC) = &HFC Then
      count = 6
      N = b And &H1
    ElseIf (b And &HF8) = &HF8 Then
      count = 5
      N = b And &H3
    ElseIf (b And &HF0) = &HF0 Then
      count = 4
      N = b And &H7
    ElseIf (b And &HE0) = &HE0 Then
      count = 3
      N = b And &HF
    ElseIf (b And &HC0) = &HC0 Then
      count = 2
      N = b And &H1F
    Else
      count = 1
      str = str & Chr(b)
    End If

    If i + count - 1 > bslen Then
      str = str&"?"
      Exit Do
    End If

    If count>1 then
      For k = 1 To count - 1
        b = AscB(MidB(bytes,i+k+1,1))
        N = N * &H40 + (b And &H3F)
      Next
      str = str & ChrW(N)
    End If
    i = i + count
  Loop

  BytesToString = str
End Function

Tín dụng vào Tải lên tệp Pure ASP bằng cách triển khai BytesToString()chức năng từ include_aspuploader.aspmã của riêng tôi, tôi có thể làm cho UTF-8tên tệp hoạt động.


Liên kết hữu ích


-1

Chúng tôi đã gặp một vấn đề tương tự trong một ứng dụng web và đã kết thúc bằng cách đọc tên tệp từ HTML <input type="file">và đặt nó ở dạng được mã hóa url trong một HTML mới <input type="hidden">. Tất nhiên, chúng tôi đã phải xóa đường dẫn như "C: \ fakepath \" được trả lại bởi một số trình duyệt.

Tất nhiên điều này không trả lời trực tiếp câu hỏi của OP, nhưng có thể là một giải pháp cho những người khác.


1
Vấn đề hoàn toàn khác nhau. Câu hỏi là về tải xuống , trả lời của bạn là về tải lên .
Oskar Berggren

-3

Tôi thường mã hóa URL (với% xx) tên tệp và dường như nó hoạt động trong tất cả các trình duyệt. Bạn có thể muốn làm một số thử nghiệm nào.


10
Tôi đã thử nghiệm trong một vài và nó không hoạt động theo cách đó trong tất cả các trình duyệt, do đó, câu hỏi. :)
Atif Aziz
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.