589

Webブラウザーで直接レンダリングするのではなく、強制的にリソースをダウンロードする Web アプリケーションは、次の形式の HTTP 応答でヘッダーを発行します。Content-Disposition

Content-Disposition: attachment; filename=FILENAME

このfilenameパラメータを使用して、ブラウザによってリソースがダウンロードされるファイルの名前を提案できます。ただし、 RFC 2183 (Content-Disposition) では、セクション 2.3 (ファイル名パラメーター) で、ファイル名には US-ASCII 文字のみを使用できると記載されています。

現在の [RFC 2045] の文法では、パラメータ値 (したがって Content-Disposition ファイル名) が US-ASCII に制限されています。ファイル名に任意の文字セットを許可することが非常に望ましいことは認識していますが、必要なメカニズムを定義することはこのドキュメントの範囲を超えています。

それにもかかわらず、今日のほとんどの一般的な Web ブラウザーは、非 US-ASCII 文字を許可しているように見えますが、(標準がないため) ファイル名のエンコード方式と文字セットの仕様に同意していないという経験的な証拠があります。問題は、ファイル名「naïvefile」(引用符なしで、3 番目の文字が U+00EF) を Content-Disposition ヘッダーにエンコードする必要がある場合、一般的なブラウザーで採用されているさまざまなスキームとエンコーディングは何ですか?

この質問の目的のために、一般的なブラウザは次のとおりです。

  • グーグルクローム
  • サファリ
  • Internet Explorer または Edge
  • ファイアフォックス
  • オペラ
4

21 に答える 21

406

これは古い投稿であることは知っていますが、それでも非常に関連性があります。最近のブラウザは rfc5987 をサポートしており、utf-8 エンコーディング、パーセンテージ エンコーディング (url エンコーディング) が可能であることがわかりました。Naïve file.txt は次のようになります。

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

Safari (5) はこれをサポートしていません。代わりに、utf-8 でエンコードされたヘッダーにファイル名を直接書き込む Safari 標準を使用する必要があります。

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

IE8 以前でもサポートされていないため、IE 標準の utf-8 エンコーディング、パーセンテージ エンコーディングを使用する必要があります。

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

ASP.Net では、次のコードを使用します。

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);

IE7、IE8、IE9、Chrome 13、Opera 11、FF5、Safari 5 を使用して上記をテストしました。

2013 年 11 月の更新:

ここに私が現在使用しているコードがあります。まだ IE8 をサポートしなければならないので、最初の部分を取り除くことはできません。Android のブラウザーは組み込みの Android ダウンロード マネージャーを使用しており、標準的な方法ではファイル名を確実に解析できないことが判明しました。

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);

上記は現在、IE7-11、Chrome 32、Opera 12、FF25、Safari 6 でテストされており、ダウンロードに次のファイル名を使用しています: ^~'-_,;.txt

IE7 では一部の文字で機能しますが、すべてではありません。しかし、最近では誰が IE7 を気にかけているでしょうか?

これは、Android 用の安全なファイル名を生成するために使用する関数です。Android でサポートされている文字はわかりませんが、これらが確実に機能することをテストしたことに注意してください。

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: IE7 と IE8 でテストしたところ、アポストロフィ (') をエスケープする必要がないことがわかりました。失敗した例はありますか?

@Dave Van den Eynde: RFC6266 に従って 2 つのファイル名を 1 行に結合すると、Android と IE7+8 以外で機能します。これを反映するようにコードを更新しました。提案していただきありがとうございます。

@Thilo: GoodReader やその他の非ブラウザーについてはわかりません。Android のアプローチを使用すると、運が良いかもしれません。

@Alex Zhukovskiy: 理由はわかりませんが、Connectで説明されているように、うまく機能していないようです。

于 2011-07-19T10:34:35.950 に答える
178
  • で非ASCII名をエンコードする相互運用可能な方法はありませんContent-Dispositionブラウザの互換性はめちゃくちゃです。

  • でUTF-8を使用するための理論的に正しい構文Content-Dispositionは非常に奇妙です:(filename*=UTF-8''foo%c3%a4はい、それはアスタリスクであり、真ん中の空の一重引用符を除いて引用符はありません)

  • このヘッダーはちょっと標準的ではありません(HTTP / 1.1仕様はその存在を認めていますが、クライアントがそれをサポートする必要はありません)。

シンプルで非常に堅牢な代替手段があります。必要なファイル名を含むURLを使用します

最後のスラッシュの後の名前が必要な名前である場合、余分なヘッダーは必要ありません。

このトリックは機能します:

/real_script.php/fake_filename.doc

また、サーバーがURL書き換えをサポートしている場合(mod_rewriteApacheなど)、スクリプト部分を完全に非表示にすることができます。

URLの文字は、バイトごとにurlencodedされたUTF-8である必要があります。

/mot%C3%B6rhead   # motörhead
于 2008-10-19T18:26:36.530 に答える
102

これについては、ブラウザのテストへのリンクや下位互換性など、提案されているRFC 5987「ハイパーテキスト転送プロトコル(HTTP)ヘッダーフィールドパラメータの文字セットと言語エンコーディング」で説明されています。

RFC 2183は、そのようなヘッダーはRFC 2184に従ってエンコードする必要があることを示しています。これは、 RFC 2231によって廃止され、上記のドラフトRFCでカバーされています。

于 2008-09-18T15:39:58.607 に答える
78

RFC 6266 では、「<em>Hypertext Transfer Protocol (HTTP) での Content-Disposition ヘッダー フィールドの使用」について説明しています。そこから引用:

6. 国際化に関する考慮事項

「<code>filename*」パラメーター (セクション 4.3 ) は、[ RFC5987 ] で定義されたエンコーディングを使用して、サーバーが ISO-8859-1 文字セット外の文字を送信できるようにし、オプションで使用中の言語を指定することもできます。

そして彼らの例のセクションでは:

この例は上記の例と同じですが、 RFC 5987を実装していないユーザー エージェントとの互換性のために「filename」パラメーターを追加しています。

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

注: RFC 5987エンコーディングをサポートしないユーザー エージェントは、 "<code>filename" の後に出現する "<code>filename*" を無視します。

付録 Dには、相互運用性を高めるための提案の長いリストもあります。また、実装を比較するサイトも指しています。一般的なファイル名に適した現在のオールパス テストには、次のものがあります。

  • attwithisofnplain : ISO-8859-1 のプレーンなファイル名で、二重引用符があり、エンコードされていません。これには、すべて ISO-8859-1 であり、少なくとも 16 進数の前にパーセント記号を含まないファイル名が必要です。
  • attfnboth : 上記の順序で 2 つのパラメーター。IE8 は「<code>filename」パラメーターを使用しますが、ほとんどのブラウザーでほとんどのファイル名に対して機能するはずです。

そのRFC 5987は、実際の形式を説明するRFC 2231を参照しています。2231 は主にメール用で、5987 は HTTP ヘッダーにも使用できる部分を示しています。これを、 RFC 2388 (特にセクション 4.4 ) およびHTML 5 ドラフトによって管理されているmultipart/form-dataHTTP本文内で使用される MIME ヘッダーと混同しないでください。

于 2014-01-05T12:48:27.443 に答える
16

Jimが回答で言及したドラフト RFCからリンクされた次のドキュメントは、この質問にさらに対処しており、ここで直接注目する価値があります。

HTTP Content-Disposition ヘッダーおよび RFC 2231/2047 エンコーディングのテスト ケース

于 2008-09-18T16:08:16.900 に答える
14

ファイル名を二重引用符で囲みます。私の問題を解決しました。このような:

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

http://kb.mozillazine.org/Filenames_with_spaces_are_truncated_upon_download

複数のオプションをテストしました。ブラウザーは仕様をサポートしておらず、動作も異なります。二重引用符が最適なオプションだと思います。

于 2015-07-10T15:01:51.320 に答える
13

エンコードには次のコード スニペットを使用します ( fileNameにファイル名とファイルの拡張子が含まれていると仮定します。つまり、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 ) );
}

ジャワ:

fileName = request.getHeader ( "user-agent" ).contains ( "MSIE" ) ? URLEncoder.encode ( fileName, "utf-8") : MimeUtility.encodeWord ( fileName );
response.setHeader ( "Content-disposition", "attachment; filename=\"" + fileName + "\"");
于 2013-04-19T11:29:24.367 に答える
11

asp.net mvc2 では、次のようなものを使用します。

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

mvc(2) を使用しない場合は、次を使用してファイル名をエンコードするだけでよいと思います

HttpUtility.UrlPathEncode(fileName)
于 2010-07-15T15:08:29.073 に答える
5

古いエクスプローラーを含むすべての主要なブラウザーで(互換モードを介して)次のコードをテストしましたが、どこでも正常に機能します。

$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.'"');
于 2012-05-31T15:48:11.457 に答える
5

「download.php」スクリプトで次のコードになりました(このブログ投稿これらのテストケースに基づいています)。

$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) ));

iso-latin1 と「安全な」文字のみが使用されている限り、これは filename="..." の標準的な方法を使用します。そうでない場合は、filename*=UTF-8'' URL エンコード方式を追加します。この特定のテスト ケースによると、MSIE9 以降、および最近の FF、Chrome、Safari で動作するはずです。下位の MSIE バージョンでは、ファイル名の ISO8859-1 バージョンを含むファイル名を提供する必要があります。このエンコーディングにない文字にはアンダースコアが付いています。

最後の注意: 最大。各ヘッダー フィールドのサイズは、apache では 8190 バイトです。UTF-8 は、1 文字あたり最大 4 バイトです。rawurlencode の後、1 文字あたり x3 = 12 バイトです。かなり非効率的ですが、ファイル名に 600 個を超える「笑顔」 %F0%9F%98%81 を含めることは理論的には可能です。

于 2015-04-05T15:45:29.043 に答える
3

PHP フレームワーク Symfony 4 に$filenameFallbackHeaderUtils::makeDisposition. 詳細については、この関数を調べることができます-上記の回答に似ています。

使用例:

$filenameFallback = preg_replace('#^.*\.#', md5($filename) . '.', $filename);
$disposition = $response->headers->makeDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, $filename, $filenameFallback);
$response->headers->set('Content-Disposition', $disposition);
于 2019-07-22T13:58:45.870 に答える
-2

私は通常、ファイル名を (%xx で) URL エンコードしますが、すべてのブラウザーで動作するようです。とにかくいくつかのテストをしたいかもしれません。

于 2008-09-18T15:28:29.493 に答える