How to Force File Download with Correct Filename Encoding Across Browsers

This article explains why forcing a download dialog while preserving the original (possibly non‑ASCII) filename requires special handling of the Content‑Disposition header, reviews relevant RFCs, compares browser behaviours, and provides a standards‑compliant solution using RFC 5987 encoding.

21CTO
21CTO
21CTO
How to Force File Download with Correct Filename Encoding Across Browsers

When implementing a forced file download that must keep the original filename (which may contain non‑ASCII characters), a simple Content‑Disposition: attachment header works, but correctly encoding the filename parameter is problematic.

The basic approach uses

Content‑Disposition: attachment; filename="$encoded_fname"; filename*=utf-8''$encoded_fname

, where $encoded_fname is the UTF‑8 filename percent‑encoded with rawurlencode() in PHP.

Older browsers such as IE6 require the original filename to include an ASCII extension, and they interpret the quoted filename as literal text, automatically decoding percent‑encoded strings when an ASCII extension is present.

Why This Works

HTTP/1.1 (RFC 2616) defines message bodies as ASCII‑only text; any non‑ASCII characters in header fields must be encoded using RFC 2047 rules, which were originally designed for MIME email and differ from percent‑encoding.

Because Content‑Disposition originated from MIME, early browsers did not support the multilingual encoding extension. Different browsers adopted incompatible work‑arounds:

IE accepts percent‑encoded strings directly in filename (e.g., filename="%e2%82%ac%20rates.txt") provided the filename has an unencoded ASCII extension.

Other browsers allow raw UTF‑8 strings in filename, violating the ASCII‑only rule.

To avoid UA detection, one could branch on the user‑agent, using the IE method for IE and the UTF‑8 method for others, but this fails for some browsers such as Opera and Safari.

RFC 5987 (2010) introduced a standard way to encode parameters with the syntax parameter*=charset'lang'value. The filename* parameter follows this rule, using percent‑encoding of the UTF‑8 value. When both filename and filename* are present, browsers must prefer filename*.

This approach maintains forward compatibility: the header remains ASCII‑only, and older browsers that ignore filename* fall back to the traditional filename handling.

RFC 6266 (2011) later standardized Content‑Disposition and reaffirmed the RFC 5987 encoding method, providing an example:

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

Modern browsers (Firefox, Chrome, Opera, Safari) support filename* and will use it if present; older IE versions ignore it and use filename, which must have an ASCII extension.

MDN Summary of Content‑Disposition

In a regular HTTP response, the Content‑Disposition header indicates whether the content should be displayed inline or treated as an attachment to be saved locally. In multipart/form‑data bodies, the header can describe each part’s disposition, name, and filename.

When used as a response header, the first parameter is either inline (default) or attachment. With attachment, browsers typically show a “Save As” dialog pre‑filled with the filename value.

Content-Disposition: inline
Content-Disposition: attachment
Content-Disposition: attachment; filename="filename.jpg"

Multipart Body Disposition

In multipart bodies, the first parameter is always form-data. Additional parameters such as name and filename are case‑insensitive, separated by semicolons, and values are quoted.

Content-Disposition: form-data; name="fieldName"
Content-Disposition: form-data; name="fieldName"; filename="filename.jpg"

Parameters

name : The form field name. If the value is _charset_, it indicates the default charset for parts without an explicit charset.

filename : The original name of the file to be transmitted. It must not contain path information and may be transformed to conform to server filesystem rules. When used with attachment, it becomes the default name in the save dialog.

filename* : Same as filename but encoded according to RFC 5987. When both are present, filename* takes precedence if supported.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

HTTPFile Downloadbrowser compatibilitycontent-dispositionheader encodingRFC 5987
21CTO
Written by

21CTO

21CTO (21CTO.com) offers developers community, training, and services, making it your go‑to learning and service platform.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.