Frage

Web-Anwendungen, die eine Ressource sein heruntergeladen nicht direkt gerendert in einem Web-Browser-Problem eines Content-Disposition Header in der HTTP-Antwort des Formulars erzwingen wollen:

Content-Disposition: attachment; filename=FILENAME

kann der filename Parameter verwendet werden, um einen Namen für die Datei vorschlagen, in denen die Ressource durch den Browser heruntergeladen wird. RFC 2183 (Content-Disposition), jedoch heißt es in Abschnitt 2.3 (der Dateiname Parameter), dass der Name Datei nur US-ASCII-Zeichen verwenden kann:

  

Current [RFC 2045] Grammatik engt   Parameterwerte (und somit   Content-Disposition Dateinamen) zu   US-ASCII. Wir erkennen die große   Wünschbarkeit ermöglicht beliebigen   Zeichensätze in Dateinamen, aber es ist   über den Rahmen dieses Dokuments   definiert die notwendigen Mechanismen.

Es gibt empirische Belege dafür, doch die beliebtestenen Web-Browser nicht-US-ASCII-Zeichen scheinen heute noch zu ermöglichen (für das Fehlen eines einheitlichen Standard) nicht einverstanden ist auf dem Codierungsschema und Zeichensatz-Spezifikation des Dateinamen. Die Frage ist dann, was sind die verschiedenen Regelungen und beschäftigt Codierungen von den gängigen Browsern, wenn der Dateiname „naïvefile“ (ohne Anführungszeichen und wo der dritte Buchstabe U + 00EF) benötigt in den Content-Disposition-Header verschlüsselt werden?

Für die Zwecke dieser Frage, populärer Browser Wesen:

  • Firefox
  • Internet Explorer
  • Safari
  • Google Chrome
  • Opera
War es hilfreich?

Lösung

Es ist die Diskussion über diese, einschließlich Links zu Browser-Test und Abwärtskompatibilität, in dem vorgeschlagenen RFC 5987 "Zeichensatz und Sprachcodierung für Hypertext Transfer Protocol (HTTP) Header-Feld Parameter."

RFC 2183 zeigt an, dass eine solche Überschriften sollte entsprechend RFC 2184 , die von RFC 2231 , durch den Entwurf des RFC bedeckt oben.

Andere Tipps

Ich weiß, dass dies eine alte Post, aber es ist immer noch sehr relevant. Ich habe festgestellt, dass moderne Browser rfc5987 unterstützen, die utf-8-Codierung, Prozentsatz codiert (URL-codiert) ermöglicht. Dann Naïve file.txt wird:

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

Safari (5) unterstützt dies nicht. Stattdessen sollten Sie den Safari-Standard der die Dateinamen direkt in Ihren utf-8-codierten Header verwenden Schreiben:

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

IE8 und älter unterstützt es auch nicht, und Sie müssen den IE-Standard von UTF-8-Codierung verwenden, Prozentsatz codiert:

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

In ASP.Net Ich verwende den folgenden Code:

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

Ich testete die oben mit IE7, IE8, IE9, Chrome 13, Opera 11, FF5, Safari 5.

Aktualisieren November 2013:

Hier ist der Code, den ich zur Zeit verwenden. Ich habe immer noch IE8 zu unterstützen, so kann ich nicht von dem ersten Teil loszuwerden. Es stellt sich heraus, dass Browser auf Android verwenden, um die in Android Download-Manager gebaut und es kann nicht zuverlässig Dateinamen in der Standardmethode analysiert werden.

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

Das oben gezeigte nun getestet in IE7-11, Chrome 32, Opera 12, FF25, Safari 6, mit diesem Dateinamen zum Download: 你好 abcABCæøåÆØÅäöüïëêîâéíáóúýñ½§ # ¤% & () = `@ £ $ € {[]} + '^ ~' -_.,; txt

Auf IE7 funktioniert es für einige Zeichen, aber nicht alle. Aber wer kümmert sich um IE7 heute?

Dies ist die Funktion, die ich sicher Dateinamen für Android generieren verwenden. Beachten Sie, dass ich nicht weiß, welche Zeichen auf Android unterstützt, aber dass ich getestet habe, dass diese Arbeit sicher:

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: Getestet habe ich in IE7 und IE8 und es stellte sich heraus, dass ich nicht zu entkommen Apostroph brauchte ( '). Haben Sie ein Beispiel, wo es nicht funktioniert?

@ Dave Van den Eynde: auf einer Linie, die die zwei Dateinamen Kombination zu RFC6266 nach arbeitet außer für Android und IE7 + 8, und ich habe den Code aktualisiert dies zu reflektieren. Vielen Dank für die Anregung.

@Thilo: Keine Ahnung von Goodreader oder einem anderen Nicht-Browser. Sie könnten etwas Glück mit dem Android-Ansatz haben.

@ Alex Zhukovskiy: Ich weiß nicht, warum, aber wie auf Connect es scheint nicht schrecklich gut zu funktionieren.

  • Es gibt keine interoperable Art und Weise nicht-ASCII-Namen in Content-Disposition zu kodieren. Browser-Kompatibilität ist ein Chaos .

  • Die theoretisch korrekte Syntax für die Verwendung von UTF-8 in Content-Disposition ist sehr seltsam: filename*=UTF-8''foo%c3%a4 (ja, das ist ein Stern, und ohne Anführungszeichen, außer einem leeren Apostroph in der Mitte)

  • Dieser Header ist irgendwie-nicht-ganz-Standard (

    RFC 6266 beschreibt die „ Die Verwendung des Content-Disposition-Header-Feldes in dem Hypertext Transfer Protocol (HTTP ) “. Zitiert aus, dass:

      

    6. Internationalisierung Überlegungen

         

    Die „filename*“ Parameter ( Abschnitt 4.3 ), unter Verwendung der Codierung definiert   in [ RFC5987 ], kann der Server Zeichen außerhalb des zu übermitteln   ISO-8859-1-Zeichensatz, und auch optional die Sprache angeben   in Gebrauch ist.

    Und in ihren Beispiele Abschnitt :

      

    Dieses Beispiel ist das gleiche wie die oben, aber das Hinzufügen des „Dateinamen“   Parameter für die Kompatibilität mit Benutzeragenten nicht Umsetzung    RFC 5987 :

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

    Hinweis: Die Benutzeragenten, die die RFC 5987 nicht Codierung unterstützen   ignorieren „filename*“, wenn es auftritt, nachdem „filename“.

    Anhang D gibt es auch eine lange Liste von Vorschlägen Interoperabilität zu erhöhen. Er verweist auch auf eine Website, die vergleicht Implementierungen . Aktuelle Allpass-Tests geeignet für allgemeine Dateinamen sind:

    • attwithisofnplain : plain ISO-8859-1 Dateiname mit doppelten Anführungszeichen und ohne Codierung. Dies erfordert einen Dateinamen, die alle ISO-8859-1 ist und enthält keine Prozentzeichen, zumindest nicht vor hexadezimalen Ziffern.
    • attfnboth : zwei Parameter in der oben beschriebenen Reihenfolge. Sollte funktionieren für die meisten Dateinamen auf den meisten Browsern, obwohl IE8 die „filename“ Parameter verwenden.

    Das RFC 5987 wiederum Referenzen RFC 2231 , die das eigentliche Format beschreibt. 2231 ist in erster Linie für Mail und 5987 sagt uns, welche Teile für HTTP-Header als auch verwendet werden können. Verwechseln Sie dies nicht mit MIME-Header in einem multipart/form-data HTTP verwendet Körper , die von RFC 2388 geregelt ( Abschnitt 4.4 insbesondere) und die HTML 5 Entwurf .

Das folgende Dokument verknüpft dem Entwurf RFC von Jim in seiner Antwort erwähnt richtet sich weiter die Frage und auf jeden Fall eine direkte Note hier wert:

Testfälle für HTTP-Content-Disposition-Header und RFC 2231/2047 Encoding

in asp.net MVC2 ich verwende etwas wie folgt aus:

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

Ich denke, wenn Sie nicht Mvc verwenden (2) Sie könnten nur die Dateinamen kodieren mit

HttpUtility.UrlPathEncode(fileName)

Setzen Sie die Dateinamen in doppelten Anführungszeichen. Gelöst ist das Problem für mich. Wie folgt aus:

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

http://kb.mozillazine.org/Filenames_with_spaces_are_truncated_upon_download

Ich habe mehrere Optionen geprüft. Browser unterstützt nicht die Spezifikationen und handelt anders, glaube ich doppelte Anführungszeichen die beste Option ist.

Ich verwende den folgenden Code-Schnipsel für die Codierung (vorausgesetzt filename enthält die Dateinamen und die Erweiterung der Datei, d.h .: 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 + "\"");

In ASP.NET Web API, URL ich die Dateinamen kodieren:

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 nicht festgelegt
IE 9 Fixed

Ich testete den folgenden Code in allen gängigen Browsern, einschließlich älteren Explorers (über den Kompatibilitätsmodus), und es funktioniert gut überall:

$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.'"');

Wenn Sie ein NodeJS Backend verwenden, können Sie den folgenden Code verwenden, fand ich hier

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

ich mit dem folgenden Code in meinem "download.php" Skript (basierend auf diese Blogpost und diese Testfälle ).

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

Dies verwendet die Standardmethode der Dateiname = „...“ solange es nur iso-latin1 und ‚sichere‘ Zeichen verwendet; wenn nicht, fügt sie den Dateinamen * = UTF-8 '' URL-codiert Art und Weise. Nach dieser speziellen Testfall , sollte es aus MSIE9 aufzuarbeiten und auf den letzten FF, Chrome , Safari; auf niedrigere MSIE Version, sollte es Dateinamen enthalten die ISO8859-1 Version des Dateinamen, mit Unterstrichen auf Zeichen, die nicht in dieser Codierung bieten.

Schlussbemerkung: der max. Größe für jedes Header-Feld ist 8190 Bytes auf Apache. UTF-8 können bis zu vier Bytes pro Zeichen sein; nach rawurlencode ist es x3 = 12 Bytes pro Zeichen. Ziemlich ineffizient, aber es sollte noch theoretisch möglich sein, mehr als 600 zu haben „schmunzelt“% F0% 9F% 98% 81 im Dateinamen.

In PHP tat dies es für mich (vorausgesetzt, den Dateinamen wird UTF8 codiert):

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

Getestet gegen IE8-11, Firefox und Chrome.
Wenn der Browser interpretieren kann Dateiname * = utf-8 wird es die UTF8-Version des Dateinamen verwenden, sonst wird es die dekodiert Dateinamen verwenden. Wenn der Dateiname Zeichen enthält, die nicht in ISO-8859-1 dargestellt werden kann, mögen Sie vielleicht stattdessen mit iconv berücksichtigen.

Classic ASP-Lösung

Die meisten modernen Browser unterstützen das Bestehen der Filename als UTF-8 jetzt aber wie es der Fall mit einer Lösung Datei-Upload war ich, dass verwenden basierte auf FreeASPUpload.Net (Site nicht mehr vorhanden, Link verweist auf archive.org ) es wäre nicht als Parsing der binären arbeiten beim Lesen Single-Byte-ASCII-kodierten Strings verlassen, die gut funktioniert, wenn Sie bestanden UTF-8 kodierten bis Sie Daten Zeichen erhalten ASCII nicht unterstützt werden.

Allerdings war ich in der Lage, eine Lösung zu finden, um den Code zu bekommen die binären als UTF-8 zu lesen und zu analysieren.

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

Kredit geht an reine ASP-Datei hochladen durch die BytesToString() Funktion von include_aspuploader.asp in meinem eigenen Code I Umsetzung war in der Lage UTF-8 Dateinamen arbeiten.

bekommen

Nützliche Links

Nur ein Update, da ich all diese Dinge heute in Reaktion auf ein Kundenproblem

versuche
  • Mit Ausnahme von Safari für Japanisch konfiguriert, alle Browser unsere Kunden am besten mit filename = text.pdf arbeitete getestet - wo Text ein Kundenwert von ASP.Net/IIS in utf-8 ohne URL-Codierung serialisiert ist. Aus irgendeinem Grund, Safari für Englisch konfiguriert würde akzeptieren und speichern ordnungsgemäß eine Datei mit utf-8 japanischen Namen, aber dem gleichen Browser für Japanisch konfiguriert würde die Datei mit den utf-8 Zeichen uninterpretiert speichern. All anderer Browser getestet schien am besten / gut zu funktionieren (unabhängig von der Sprache Konfiguration) mit dem Dateinamen utf-8 ohne URL-Codierung codiert.
  • Ich konnte keinen einzigen Browser-Implementierung Rfc5987 / 8187 an alle finden. Ich mit der neuesten Chrome getestet, baut Firefox und IE 11 und Kante stricken. Ich habe versucht, den Header mit nur Dateinamen * = utf-8''texturlencoded.pdf Einstellung, es mit beiden filename = text.pdf Einstellung; Dateiname * = utf-8''texturlencoded.pdf. Nicht ein Merkmal Rfc5987 / 8187 erschien korrekt in einem der obigen Punkte zu verarbeiten zu werden.

Wir hatten ein ähnliches Problem in einer Web-Anwendung, und am Ende durch den Dateinamen aus dem HTML-<input type="file"> zu lesen, und dass in einem neuen HTML <input type="hidden"> in der URL-kodierter Form einstellen. Natürlich hatten wir den Pfad wie „C: \ fakepath \“ zu entfernen, die von einigen Browsern zurückgegeben.

Natürlich bedeutet dies nicht direkt OPs Frage beantworten, sondern kann auch eine Lösung für andere sein.

ich normalerweise URL-Codierung (mit% xx) die Dateinamen, und es scheint, in allen Browsern zu arbeiten. Sie könnten einige Tests wollen auf jeden Fall tun.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top