C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

文字化けする画像ファイルヘッダー

[トピック内 23 記事 (1 - 20 表示)]  << 0 | 1 >>

■88724 / inTopicNo.1)  文字化けする画像ファイルヘッダー
  
□投稿者/ ひょっとこ (1回)-(2018/09/22(Sat) 10:12:01)

分類:[.NET 全般] 


HTMLファイルを作成し、

<!DOCTYPE html>
<img src="http://cms1.ishikawa-c.ed.jp/~shough/NC2/htdocs/?action=common_download_main&amp;upload_id=4537" alt="" />
</html>

と書きます。
作成したHTMLファイルをIEで開き、画像の上で右クリックメニューから
画像の保存を行います。
するとファイル名は
DSC_0063 - コピー北國新聞社社長賞.JPG
となります。

このファイル名はHTMLファイル内には記述していないので
恐らく、ファイルヘッダーから取得したのだと思います。

どこのサイトで調べたのかは忘れましたが、
以下のコードでヘッダーからファイル名を取得することができます。


これで取得するとファイル名は

"DSC_0063 - &atilde;" & ChrW(130) & "&sup3;&atilde;" & ChrW(131) & ChrW(148) & "&atilde;" & ChrW(131) & "&frac14;&aring;" & ChrW(140) & ChrW(151) & "&aring;" & ChrW(156) & ChrW(139) & "&aelig;" & ChrW(150) & "°&egrave;" & ChrW(129) & ChrW(158) & "&ccedil;&curren;&frac34;&ccedil;&curren;&frac34;&eacute;" & ChrW(149) & "&middot;&egrave;&sup3;" & ChrW(158) & ".JPG"

になってしまいます。
半角英数字はうまく取得できているのですが、
全角文字のところが全て文字化けしてしまってうまく取得することができません。

どのようにすれば、うまく取得できますか?


Sub Main()


   Dim FileName As String = AcquireFileNameFromHeader(HttpUtility.HtmlDecode("http://cms1.ishikawa-c.ed.jp/~shough/NC2/htdocs/?action=common_download_main&amp;upload_id=4537"))


End Sub



    Function AcquireFileNameFromHeader(URL$) As String


            Dim req As HttpWebRequest = CType(WebRequest.Create(URL), HttpWebRequest)

            Dim fileName As String = ""


            Dim res As HttpWebResponse = CType(req.GetResponse(), HttpWebResponse)

            Dim dispos As String = res.Headers("Content-Disposition")

            If Not String.IsNullOrEmpty(dispos) Then

                Dim re As New Regex(
                      "filename\s*=\s*           " &
                      "(?:                       " &
                      "  ""(?<filename>[^""]*)"" " &
                      "  |                       " &
                      "  (?<filename>[^;]*)      " &
                      ")                         " _
                      , RegexOptions.IgnoreCase _
                  Or RegexOptions.IgnorePatternWhitespace)

                Dim m As Match = re.Match(dispos)
                If m.Success Then
                    fileName = m.Groups("filename").Value
                End If
            End If



            If Not (res Is Nothing) Then
                res.Close()
            End If


            Return fileName

    End Function



引用返信 編集キー/
■88725 / inTopicNo.2)  Re[1]: 文字化けする画像ファイルヘッダー
□投稿者/ WebSurfer (1600回)-(2018/09/22(Sat) 10:27:41)
No88724 (ひょっとこ さん) に返信

> このファイル名はHTMLファイル内には記述していないので
> 恐らく、ファイルヘッダーから取得したのだと思います。

要求・応答ヘッダ―の中身を見るのが目的で、それを取得するための方法は問わないというこ
とであれば Fiddler を使うのがお勧めです。

Fiddler のお勧め
http://surferonwww.info/BlogEngine/post/2011/05/25/Recommendation-of-Fiddler.aspx

IE なら F12 開発者ツールを使っても取得できます・・・が、使いにくいので Fiddler をお
勧めします。
引用返信 編集キー/
■88726 / inTopicNo.3)  Re[2]: 文字化けする画像ファイルヘッダー
□投稿者/ ひょっとこ (2回)-(2018/09/22(Sat) 10:40:57)
VB.NET上で取得する必要があるので
他のソフトウェアは使いたくないのですが・・・・
よろしくお願いいたします。
引用返信 編集キー/
■88727 / inTopicNo.4)  Re[3]: 文字化けする画像ファイルヘッダー
□投稿者/ WebSurfer (1601回)-(2018/09/22(Sat) 10:59:05)
No88726 (ひょっとこ さん) に返信
> VB.NET上で取得する必要があるので
> 他のソフトウェアは使いたくないのですが・・・・
> よろしくお願いいたします。

そうですか・・・

でも、やっぱり Fiddler を使ってみることをお勧めします。それで応答ヘッダ―を見ると文字化けの
原因が分からるかも。最低でも何らかのヒントは得られるはずです。
引用返信 編集キー/
■88730 / inTopicNo.5)  Re[3]: 文字化けする画像ファイルヘッダー
□投稿者/ WebSurfer (1602回)-(2018/09/22(Sat) 14:12:21)
No88726 (ひょっとこ さん) に返信

何故 Fiddler で見るように言ったのか理解されていないようなので追加情報を書いておきます。

応答ヘッダの Content-Disposition の filename にファイル名が設定されていると思いますが、
IE の場合「DSC_0063 - コピー北國新聞社社長賞.JPG」のような ASCII 文字でない日本語をそ
のまま filename に設定すると文字化けするはずです。

それを回避するため「コピー北國新聞社社長賞」の部分はパーセントエンコーディングしている
と思います。

さらに、RFC 6266 に準拠した設定がされているかもしれません。その場合 filename は以下の
ようになります。

filename*=utf-8''DSC_0063 - %e3%82%b3%e3%83%94%e3%83%bc%e5%8c%97%e5%9c%8b%e6%96%b0%e8%81%9e%e7%a4%be%e7%a4%be%e9%95%b7%e8%b3%9e.JPG

HttpWebResponse はデコードしてくれません。res.Headers("Content-Disposition") で取得する
とそのまま出てきます。

質問者さんのコースで上記のことが当てはまるのかは分かりませんが、何にせよ、Fiddler で直接
応答ヘッダーを見てそういうところを調べないと暗中模索で解決になかなかたどり着けません。
引用返信 編集キー/
■88731 / inTopicNo.6)  Re[1]: 文字化けする画像ファイルヘッダー
□投稿者/ 魔界の仮面弁士 (1852回)-(2018/09/22(Sat) 14:29:16)
No88724 (ひょっとこ さん) に返信
> どこのサイトで調べたのかは忘れましたが、
> 以下のコードでヘッダーからファイル名を取得することができます。

恐らく下記では無いでしょうか。見覚えはありますか?
http://www.atmarkit.co.jp/fdotnet/dotnettips/618downnoname/downnoname.html

上記には URL$ という名の引数は出てこないので、自前で書き直した記憶が無ければ、
上記を元に二次加工されたソースだったのかも知れませんが。


> Dim req As HttpWebRequest = CType(WebRequest.Create(URL), HttpWebRequest)
今回のように、ヘッダー情報を読み取ることだけを目的としているのであれば、
HTTP GET のままリクエストするのではなく、
 req.Method = System.Net.Http.HttpMethod.Head.Method
 'req.Method = "HEAD"
のように HTTP HEAD メソッドに変更してリクエストするべきかと思います。


> DSC_0063 - コピー北國新聞社社長賞.JPG
> このファイル名はHTMLファイル内には記述していないので
> 恐らく、ファイルヘッダーから取得したのだと思います。

参照されているのは、ファイルヘッダーではなく、HTTP 応答ヘッダーですね。

http://cms1.ishikawa-c.ed.jp/~shough/NC2/htdocs/?action=common_download_main&upload_id=4537
の画像では Exif 情報も削除されているため、ファイルヘッダーからは取得できないはず。


該当の URL にアクセスすると、Web サーバーから下記の応答が返されることを確認しました。(一部抜粋)

HTTP/1.1 200 OK
Date: Sat, 22 Sep 2018 01:46:42 GMT
Server: Apache/2.2.15 (CentOS)
Content-disposition: inline; filename="DSC_0063 - コピー北國新聞社社長賞.JPG"
Content-Length: 85599
Connection: close
Content-Type: image/jpeg


この時、filename= の後続のカナ漢字部分が UTF-8 エンコーディングになっていたので、
これが文字化けの原因ですね。

そしてこれは、Web サーバー側の処理に問題があるように思います。

HTTP ヘッダでの利用が許可されているのは、現時点では ISO-8859-1 のみですので、
UTF-8 でエンコードされた文字列が返されるのは、本来は NG のはずです。

2011年6月に RFC 6266 で定められるまでは、ファイル名に使われる非 ASCII 文字を
Content-Disposition: にどのように組み込むかが明確に定義されておらず、
各ブラウザーで解釈が異なっていたのですけれど、それは昔の話。

現在では、日本語ファイル名なら RFC 6266 / RFC 5987 に従って、filename= ではなく filename*= を用いた
Content-disposition: inline; filename*=utf-8'ja-jp'DSC_0063%20-%20%E3%82%B3%E3%83%94%E3%83%BC%E5%8C%97%E5%9C%8B%E6%96%B0%E8%81%9E%E7%A4%BE%E7%A4%BE%E9%95%B7%E8%B3%9E.JPG
などの応答を Web サーバーが返却するのが正しい手順であろうかと思います。
(ブラウザーによっては、"%20" の部分が " " にデコードされずに残る事もあるようですが)


もしも仮に、上記のヘッダーで返却されていたのだとしたら、受信した文字列を
下記の Uri.UnescapeDataString などでデコードすることで、正しく取得できるようになる見込みです。
https://dobon.net/vb/dotnet/internet/urlencode.html

ただしサーバーの実装が正しかったとしても、filename*= で utf-8 以外が指定されていた場合は、
HttpUtility.UrlDecodeToBytes(String, Encoding) してから
Encoding.Unicode.GetString( Byte() ) で復元する必要がありますし、
そもそも No88724 の正規表現のままでは不足なので、いずれにしてももう少し手直しは必要です。



閑話休題。

話をまとめると、文字化けの原因は、サーバー側がファイル名 UTF-8 で返しているからであり、
それを取得するための機能は、WebRequest クラスには存在しないという結論になります。

WebRequest クラスには、ContentEncoding ならありますが、
HeaderEncoding プロパティはありませんので…。


代替手段を考えてみたのですが、今のところは、サーバーと会話する処理を
自前で書くぐらいしか思い当たりませんでした。

以下は、リダイレクトやエラー処理、SSL 対応、プロキシ指定等は考慮せず、
あくまでも今回の URL に限定させた最低限の手抜き実装ですが、一応参考までに。


'Imports System
'Imports System.IO
'Imports System.Net
'Imports System.Net.Sockets
'Imports System.Text
'Imports System.Text.RegularExpressions

Function AcquireFileNameFromUTF8Header(url As String) As String
    Dim headers As String()

    Dim u As New Uri(url)
    Using client As New TcpClient()
        client.Connect(u.Host, u.Port)
        Using stm As NetworkStream = client.GetStream()
            Dim wrt As New StreamWriter(stm)
            wrt.WriteLine("HEAD " & u.ToString() & " HTTP/1.1")
            wrt.WriteLine("Host: " & u.Host)
            wrt.WriteLine("Connection: close")
            wrt.WriteLine("")
            wrt.WriteLine("")
            wrt.WriteLine("")
            wrt.Flush()

            'UTF-8 で喋るサイトのために、無理矢理 UTF-8 でデコードしています。
            Dim rdr As New StreamReader(stm, Encoding.UTF8)
            headers = rdr.ReadToEnd().Split(New String() {vbCrLf}, StringSplitOptions.RemoveEmptyEntries)
        End Using
    End Using

    Dim cd = headers.FirstOrDefault(Function(h) h.ToLowerInvariant().StartsWith("content-disposition:"))
    If Not String.IsNullOrWhiteSpace(cd) Then
        'ここの正規表現は、元の正規表現のままで、特に弄っていません。
        Dim re As New Regex( _
                  "filename\s*=\s*           " & _
                  "(?:                       " & _
                  "  ""(?<filename>[^""]*)"" " & _
                  "  |                       " & _
                  "  (?<filename>[^;]*)      " & _
                  ")                         " _
                  , RegexOptions.IgnoreCase _
              Or RegexOptions.IgnorePatternWhitespace)

        Dim m As Match = re.Match(cd)
        If m.Success Then
            Return m.Groups("filename").Value
        End If
    End If
    Return String.Empty
End Function

引用返信 編集キー/
■88732 / inTopicNo.7)  Re[4]: 文字化けする画像ファイルヘッダー
□投稿者/ ひょっとこ (4回)-(2018/09/22(Sat) 14:47:13)
魔界の仮面弁士さん

ありがとうございます。

試してみたのですが、

req.Method = System.Net.Http.HttpMethod.Head.Method
と入れると


エラー	BC30456	'Http' は 'System.Net' のメンバーではありません。

というエラーが発生してしまうのですが。



更に、作成くださったFunctionを使ってみたのですが

        Dim fff3 = AcquireFileNameFromUTF8Header("http://cms1.ishikawa-c.ed.jp/~shough/NC2/htdocs/?action=common_download_main&amp;upload_id=1545")

とやっても、出力結果は空の文字列になってしまうのですが。


更に、

URLデコードも試してみたのですが
半角文字→全角文字への変換ができないのですが。

    Function AcquireFileNameFromHeader(URL$) As String

            Dim req As HttpWebRequest = CType(WebRequest.Create(URL), HttpWebRequest)
            '  req.Method = System.Net.Http.HttpMethod.Head.Method

            Dim fileName As String = ""



            Dim res As HttpWebResponse = CType(req.GetResponse(), HttpWebResponse)

            ' ヘッダ情報からファイル名の取得
            Dim dispos As String = res.Headers("Content-Disposition")


            Dim dispos2 = System.Web.HttpUtility.UrlDecode(dispos)
            Dim dispos3 = Uri.UnescapeDataString(dispos)


            If Not String.IsNullOrEmpty(dispos) Then

                ' filename=<ファイル名>の抜き出し
                Dim re As New Regex(
                      "filename\s*=\s*           " &
                      "(?:                       " &
                      "  ""(?<filename>[^""]*)"" " &
                      "  |                       " &
                      "  (?<filename>[^;]*)      " &
                      ")                         " _
                      , RegexOptions.IgnoreCase _
                  Or RegexOptions.IgnorePatternWhitespace)

                Dim m As Match = re.Match(dispos)
                If m.Success Then
                    fileName = m.Groups("filename").Value
                End If
            End If



            '閉じる
            If Not (res Is Nothing) Then
                res.Close()
            End If


            Return fileName


    End Function



あと、今回の問題は
本来ISO-8859-1でエンコードするべきところをUTF-8でエンコードしてあったことが原因であることは分かったのですが、
IE上だと正常に認識できて、ファイル名を正常に取得できています。

いったい、どうやってIEはISO-8859-1とUTF-8を認識しているのでしょうか?

引用返信 編集キー/
■88733 / inTopicNo.8)  Re[4]: 文字化けする画像ファイルヘッダー
□投稿者/ 魔界の仮面弁士 (1853回)-(2018/09/22(Sat) 15:00:12)
No88730 (WebSurfer さん) に返信
> さらに、RFC 6266 に準拠した設定がされているかもしれません。その場合 filename は以下の
> ようになります。
> filename*=utf-8''DSC_0063 - %e3%82%b3%e3%83%94%e3%83%bc%e5%8c%97%e5%9c%8b%e6%96%b0%e8%81%9e%e7%a4%be%e7%a4%be%e9%95%b7%e8%b3%9e.JPG

仕様上は " - " ではなく "%20-%20" だと思っていました。

意図的に " " を使うケースがあることは理解していますが、
RFC 5987 の Section 3.2.1.を見る限りでは、半角空白は
pct-encoded ではなく attr-char のようですし、
RFC 6266 の Section 5 でも、下記のように %20 が使われていたので。

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

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

引用返信 編集キー/
■88734 / inTopicNo.9)  Re[2]: 文字化けする画像ファイルヘッダー
□投稿者/ WebSurfer (1603回)-(2018/09/22(Sat) 15:01:14)
No88731 (魔界の仮面弁士 さん) に返信

> 該当の URL にアクセスすると、Web サーバーから下記の応答が返されることを確認しました。(一部抜粋)

使ったブラウザは何ですか? IE では文字化けするはずなのですか? Chrome を使ったとか?

IE で ASCII 文字以外を filename に設定すると文字化けする理由は下記の記事を見てください。

ファイルをダウンロードする ASP.NET ページで日本語ファイル名が文字化けする
https://support.microsoft.com/ja-jp/help/436616

Downloads and International Filenames
https://blogs.msdn.microsoft.com/ieinternals/2010/06/07/downloads-and-international-filenames/

自分も、

http://cms1.ishikawa-c.ed.jp/~shough/NC2/htdocs/?action=common_download_main&upload_id=4537

を Windows 10 Pro 64-bit, IE11 で Fiddler でキャプチャしてみましたが、応答ヘッダは以下
のようになります。

Expires: Sat, 29 Sep 2018 05:37:19 GMT
Cache-Control: max-age=604800, public
Pragma: cache
Set-Cookie: nc_password=deleted; expires=Fri, 22-Sep-2017 05:37:18 GMT; path=/~shough/NC2/htdocs
Content-disposition: inline; filename="DSC_0063 - R s [ k V &#1038;В .JPG"
Etag: "541cc0-14e5f-5a360e76"
Content-Length: 85599
Connection: close
Content-Type: image/jpeg

画像を右クリックして名前を付けて保存しようとすると、

DSC_0063 - ・スR・スs・ス[・スk・ス・ス・スV・ス・ス・スミ社抵ソス・ス・ス.JPG

となります。

ちなみに Chrome は以下のようになります。文字化けはしません。

HTTP/1.1 200 OK
Date: Sat, 22 Sep 2018 05:45:00 GMT
Server: Apache/2.2.15 (CentOS)
X-Powered-By: PHP/5.3.3
Set-Cookie: nc_session=drtjda92mm19s76pjpt99stsu1; path=/~shough/NC2/htdocs
Expires: Sat, 29 Sep 2018 05:45:00 GMT
Cache-Control: max-age=604800, public
Pragma: cache
Set-Cookie: nc_password=deleted; expires=Fri, 22-Sep-2017 05:44:59 GMT; path=/~shough/NC2/htdocs
Content-disposition: inline; filename="DSC_0063 - コピー北國新聞社社長賞.JPG"
Etag: "541cc0-14e5f-5a360e76"
Content-Length: 85599
Connection: close
Content-Type: image/jpeg

質問者さん、ホントに IE を使ったのでしょうか? 話が矛盾してるようですけど。

引用返信 編集キー/
■88735 / inTopicNo.10)  Re[5]: 文字化けする画像ファイルヘッダー
□投稿者/ WebSurfer (1604回)-(2018/09/22(Sat) 15:12:15)
No88733 (魔界の仮面弁士 さん) に返信

> 仕様上は " - " ではなく "%20-%20" だと思っていました。

inline でそれだと、IE では表示された画像を右クリックして保存する際に付けられる名前に
そのまま "%20-%20" が出てきてしまいます。

ちなみに Firefox では " - " とすると DSC_0063.jpg になってしまいます。"%20-%20" は
期待通り空白になります。

要するにブラウザ依存のようです。質問者さんは IE とのことですので(ちょっと怪しいで
すが) " - " と書いておきました。

なお、attachment であれば "%20-%20" として一時ファイルに保存される名前は、IE, Chrome,
Firefox いずれも " - " になるはずです。
引用返信 編集キー/
■88736 / inTopicNo.11)  Re[3]: 文字化けする画像ファイルヘッダー
□投稿者/ ひょっとこ (6回)-(2018/09/22(Sat) 15:21:20)
ありがとうございます。

間違いなく私が使っているのはIEです。

Windows10 64bit
IE11
バージョン:11.0.15063.0


引用返信 編集キー/
■88737 / inTopicNo.12)  Re[5]: 文字化けする画像ファイルヘッダー
□投稿者/ 魔界の仮面弁士 (1854回)-(2018/09/22(Sat) 15:35:25)
No88732 (ひょっとこ さん) に返信
> req.Method = System.Net.Http.HttpMethod.Head.Method
> エラー BC30456 'Http' は 'System.Net' のメンバーではありません。

上記は、「System.Net.Http」名前空間の「HttpMethod」クラスの「Head」プロパティを
参照しているもので、コメントとして併記した
 req.Method = "HEAD"
と全く同一のものです。


> というエラーが発生してしまうのですが。
参照設定に System.Net.Http が含まれているかを確認してみてください。
https://docs.microsoft.com/ja-jp/dotnet/api/system.net.http.httpmethod

それでも駄目な場合は、.NET Framework のバージョンをご確認ください。
HttpMethod クラスは、.NET Framework 4.5 で追加されたクラスです。

ちなみに .NET Framework 4 / 4.5 / 4.5.1 のサポートは 2年半前に終了していますので、
サポート期間中の .NET Framework で HttpMethod クラスが使えないバージョンは
.NET Framework 3.5 Service Pack 1 (.NET Framework 3.5.1) のみであるはずです。


> Dim fff3 = AcquireFileNameFromUTF8Header("http://cms1.ishikawa-c.ed.jp/~shough/NC2/htdocs/?action=common_download_main&amp;upload_id=1545")
その URL を、ブラウザーのアドレスバーに入れてみた時に、正しく画像が表示されましたか?

正しいアドレスは
http://cms1.ishikawa-c.ed.jp/~shough/NC2/htdocs/?action=common_download_main&amp;upload_id=1545
ではなく
http://cms1.ishikawa-c.ed.jp/~shough/NC2/htdocs/?action=common_download_main&upload_id=1545
だったはずですよね。


> URLデコードも試してみたのですが
> 半角文字→全角文字への変換ができないのですが。
最初の、文字化けで取得された状態の文字列を、そのまま渡したりしていませんか?

Dim dispos2 = System.Web.HttpUtility.UrlDecode(dispos)
で受け渡した dispos の内容が、正しく「パーセントエンコーディングされた文字列」に
なっているかどうかを確認してみてください。
変換元の文字列が化けているようなら、そもそも復元できるはずもないわけで。

パーセントエンコードされた文字列であることは確認済みで、それでも
復元されない場合、変換元のバイナリが UTF-8 で符号化されたものでは無い可能性が
ありますので、先述した通り、HttpUtility.UrlDecodeToBytes を経由させる必要があります。


> 本来ISO-8859-1でエンコードするべきところをUTF-8でエンコードしてあったことが原因であることは分かったのですが、
> IE上だと正常に認識できて、ファイル名を正常に取得できています。
その辺の事情は先に述べた通り、RFC 6266 以前ではヘッダーの国際化対応がされていなかったことに由来します。
現在は RFC 違反だとしても、以前は未定義だったわけなので、古いサーバー実装のために、
無理矢理解釈しているといったところでしょう。

たとえば、最近の Internet Explorer では、UTF-8 なバイナリを解釈できますが、
古いバージョンの IE では、Shift_JIS 相当のバイナリとして解釈される事もあります。


> いったい、どうやってIEはISO-8859-1とUTF-8を認識しているのでしょうか?
filename*= の場合は、その後にエンコーディングが記載されています。
filename= の場合の解釈が、自動判定なのか、IE の設定依存なのかは知らないです。

文字列では無く、生のバイナリ―として取得できるのなら、EncoderExceptionFallback を
使うなどして、疑似的に文字コードを自動解釈することもできるのですが、
相手が WebRequest クラスだと、Header は自動的に String 化されてしまうので
手段がありません。相手が Body ならば、生バイナリを取得できるのですが。
引用返信 編集キー/
■88738 / inTopicNo.13)  Re[4]: 文字化けする画像ファイルヘッダー
□投稿者/ WebSurfer (1605回)-(2018/09/22(Sat) 16:43:02)
No88736 (ひょっとこ さん) に返信

> 間違いなく私が使っているのはIEです。
>
> Windows10 64bit
> IE11
> バージョン:11.0.15063.0

それは失礼しました。

とすると、保存する際、日本語の名前が文字化けしないのはヘッダーを Shift_JIS で送っているからかも
しれませんね。(未確認です)

上に紹介した記事に書いてありますが、IE は応答ヘッダ―に ASCII 以外の文字があるときは Shift_JIS と
して解釈する(日本語 OS の場合)そうですので。

自分が Fiddler を間に入れて確認した際、保存すると文字化けしたのは、Fiddler で文字化けしていたと
いうことのようです。お騒がせしてすみませんでした。

あぷりで文字化けする原因は文字コードの解釈が正しくないことにあるような気がします。(これも気がす
るだけで未検証・未確認ですが)
引用返信 編集キー/
■88739 / inTopicNo.14)  Re[4]: 文字化けする画像ファイルヘッダー
□投稿者/ ひょっとこ (8回)-(2018/09/22(Sat) 17:53:11)
ありがとうございます。

うまくいきました。

UTF-8 の場合には、AcquireFileNameFromUTF8Headerを使って、
Shift_JIS の場合には、AcquireFileNameFromHeaderを使えば良い
ということですよね?
そして、.NETのWebRequest クラスだと、これらの文字コードを認識する機能はない
ということですよね?

もし、Shift_JIS で喋るサーバーから
AcquireFileNameFromUTF8Headerを使って、取得した場合、
文字化けしてしまいますか?

もし、それが文字化けするのだとして
もし、IEがUTF-8とShift_JISのどちらのサーバーからも正常に取得できるのだとすると
IEは.NETで動いているわけではないので、
バイナリ形式で取得して、文字コードを認識しているということでしょうか?

UTF-8で喋るURLはいま手元にあるわけですが、
Shift_JIS で喋るURLがないのでテストすることができないのですが
どこかご存じでしょうか?



引用返信 編集キー/
■88740 / inTopicNo.15)  Re[6]: 文字化けする画像ファイルヘッダー
□投稿者/ 魔界の仮面弁士 (1855回)-(2018/09/22(Sat) 18:49:52)
No88734 (WebSurfer さん) に返信
>> 該当の URL にアクセスすると、Web サーバーから下記の応答が返されることを確認しました。(一部抜粋)
> 使ったブラウザは何ですか? IE では文字化けするはずなのですか? Chrome を使ったとか?

いえ。Port 80 に対して、最低限のリクエストを投げただけですね。
User-Agent や Accept-Language 等は特に送出しませんでした。

最初の質問のコードで使っている WebRequest.Create(URL) においては、
HttpWebRequest.UserAgent の初期値が Nothing だったはずなので、
それに合わせて、UA を付与せずに送出してみたということです。

WebBrowser コントロールを使うような場合であれば、IE の通信内容との差異を
チェックしたりもするのですが、今回はどちらかというと、
RFC 仕様を確認する方に注力していました。


一応、Edge 42 / Chrome 69 / Internet Explorer 11 において、
ブラウザー上から「名前を付けて保存」を行い、それらすべてが
文字化けせずに "DSC_0063 - コピー北國新聞社社長賞.JPG" という
ファイル名を提案してくることと、その時の Content-disposition が
filename*= 無しの filename= だけという事は確認していましたが、
ブラウザーへの応答時のエンコードまでは気にしていませんでした。
(ブラウザー上で処理したい訳では無かったので)



> 画像を右クリックして名前を付けて保存しようとすると、
> DSC_0063 - ・スR・スs・ス[・スk・ス・ス・スV・ス・ス・スミ社抵ソス・ス・ス.JPG
> となります。

それはおそらく、Fiddler を使ったことによるトラブルですね。

試しに、その化けてしまう画像が表示された状態のまま、
Fiddler の Capture Traffice を一時的にオフにした状態で、
IE 上で [Ctrl]+[F5] で強制リロードしてみてください。今度は正しく、
『DSC_0063 - コピー北國新聞社社長賞.JPG』で保存できる状態になると思います。



> ちなみに Chrome は以下のようになります。文字化けはしません。

先ほど追試してみたところ、"コピー" というファイル名は、
Internet Explorer 11 は、81-45,BD-52,81-45 (Shift_JIS 相当)
Edge 42 & Chrome 69 は、E3-82-B3,E3-83-94,E3-83-BC (UTF-8 相当)
で返却されてきました。

IE11 に対しても UTF-8 で返していると思い込んでいましたが、
昔も今も、対 IE 向けには Shift_JIS 前提として処理されるのですね…。


また、最初の質問にあったコードで、req.UserAgent を書き換えてみたところ、
Content-Disposition の返却結果が上記のように変わることを確認しました。

どうやら今回のサーバーは、User-Agent をチェックした上で
応答を変える仕組みになっているとみて間違いなさそうです。



No88737 (魔界の仮面弁士) に追記
> たとえば、最近の Internet Explorer では、UTF-8 なバイナリを解釈できますが、
> 古いバージョンの IE では、Shift_JIS 相当のバイナリとして解釈される事もあります。

ということで、上記は私の勘違いでした。
Internet Explorer 11 になっても、やはり Shift_JIS で解釈されるようですし、
UTF-8 エンコードな filname=〜 を解釈することはできないようです。
(filename=〜 ではなく、filename*=utf8''〜 であれば OK)



No88735 (WebSurfer さん) に返信
>>仕様上は " - " ではなく "%20-%20" だと思っていました。
> inline でそれだと、IE では表示された画像を右クリックして保存する際に付けられる名前に
> そのまま "%20-%20" が出てきてしまいます。

そうですね。そしてそれゆえに、現実的な実装として
>> 意図的に " " を使うケースがあることは理解していますが、
としているケースが少なからず存在していることは、自分も把握しているのですが、
それが RFC 仕様として許容されているものであるかどうかをご存知でしょうか、という意図です。
(各社のブラウザー仕様ではなく、HTTP Response の仕様という意味で)


> ちなみに Firefox では " - " とすると DSC_0063.jpg になってしまいます。"%20-%20" は
> 期待通り空白になります。
なるほど。ありがとうございます。
Firefox 62 は検証したことが無かったので助かりました。

RFC 仕様がどうであれ、現時点におけるサーバー側の実装としては、
未だに UA チェック(主に対 IE 向け)を行うべきなようですね。


> なお、attachment であれば "%20-%20" として一時ファイルに保存される名前は、IE, Chrome,
> Firefox いずれも " - " になるはずです。
参考になります。
引用返信 編集キー/
■88741 / inTopicNo.16)  Re[5]: 文字化けする画像ファイルヘッダー
□投稿者/ WebSurfer (1606回)-(2018/09/22(Sat) 19:02:31)
No88739 (ひょっとこ さん) に返信

自分が Fiddler を使って確認した限りですが、サーバー側で User-Agent をみて応答を変えているようです。
結果を以下に書いておきます。

そこが間違いなければ、

> UTF-8 の場合には、AcquireFileNameFromUTF8Headerを使って、
> Shift_JIS の場合には、AcquireFileNameFromHeaderを使えば良い
> ということですよね?

・・・という話にするのは無理がありそうです。


<IE11>

User-Agent:
Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko

「コピー北國新聞社社長賞」の部分のバイト列:
0xEF, 0xBF, 0xBD, 0x52, 0xEF, 0xBF, 0xBD, 0x73, 0xEF, 0xBF, 0xBD, 0x5B, 0xEF, 0xBF, 0xBD, 0x6B,
0xEF, 0xBF, 0xBD, 0xEF, 0xBF, 0xBD, 0xEF, 0xBF, 0xBD, 0x56, 0xEF, 0xBF, 0xBD, 0xEF, 0xBF, 0xBD,
0xEF, 0xBF, 0xBD, 0xD0, 0x8E, 0xD0, 0x92, 0xEF, 0xBF, 0xBD, 0xEF, 0xBF, 0xBD, 0xEF, 0xBF, 0xBD

<Chrome>

User-Agent:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36

「コピー北國新聞社社長賞」の部分のバイト列:
0xE3, 0x82, 0xB3, 0xE3, 0x83, 0x94, 0xE3, 0x83, 0xBC, 0xE5, 0x8C, 0x97, 0xE5, 0x9C, 0x8B, 0xE6,
0x96, 0xB0, 0xE8, 0x81, 0x9E, 0xE7, 0xA4, 0xBE, 0xE7, 0xA4, 0xBE, 0xE9, 0x95, 0xB7, 0xE8, 0xB3,
0x9E

<HttpWebRequest>

User-Agent:
無し

「コピー北國新聞社社長賞」の部分のバイト列:
0xE3, 0x82, 0xB3, 0xE3, 0x83, 0x94, 0xE3, 0x83, 0xBC, 0xE5, 0x8C, 0x97, 0xE5, 0x9C, 0x8B, 0xE6,
0x96, 0xB0, 0xE8, 0x81, 0x9E, 0xE7, 0xA4, 0xBE, 0xE7, 0xA4, 0xBE, 0xE9, 0x95, 0xB7, 0xE8, 0xB3,
0x9E
引用返信 編集キー/
■88742 / inTopicNo.17)  Re[7]: 文字化けする画像ファイルヘッダー
□投稿者/ WebSurfer (1607回)-(2018/09/22(Sat) 19:16:05)
No88740 (魔界の仮面弁士 さん) に返信

>> 画像を右クリックして名前を付けて保存しようとすると、
>> DSC_0063 - ・スR・スs・ス[・スk・ス・ス・スV・ス・ス・スミ社抵ソス・ス・ス.JPG
>> となります。

> それはおそらく、Fiddler を使ったことによるトラブルですね。

ご指摘の通りでした。混乱させてしまいすみません。


> どうやら今回のサーバーは、User-Agent をチェックした上で
> 応答を変える仕組みになっているとみて間違いなさそうです。

これもご指摘の通りのようです。IE と Chrome を使って結果が違うというところで
気づくべきでした。

引用返信 編集キー/
■88743 / inTopicNo.18)  Re[5]: 文字化けする画像ファイルヘッダー
□投稿者/ ひょっとこ (9回)-(2018/09/22(Sat) 19:56:51)
ありがとうございます。

IE11のUser-Agentは
Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko
なのでしょうか?
しかし、
req.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"

を追加してみましたが、やはり文字化けしてしまいます。

引用返信 編集キー/
■88744 / inTopicNo.19)  Re[6]: 文字化けする画像ファイルヘッダー
□投稿者/ WebSurfer (1608回)-(2018/09/22(Sat) 20:19:40)
No88743 (ひょっとこ さん) に返信
> ありがとうございます。
>
> IE11のUser-Agentは
> Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko
> なのでしょうか?

自分で調べてみましたか? 聞く前に調べてみましょう。

> しかし、
> req.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"
>
> を追加してみましたが、やはり文字化けしてしまいます。

魔界の仮面弁士さんが書かれたコードにあるように TcpClient レベルで正しい Encoding
を指定して取得しないと何ともならないと思います。
引用返信 編集キー/
■88746 / inTopicNo.20)  Re[6]: 文字化けする画像ファイルヘッダー
 
□投稿者/ 魔界の仮面弁士 (1857回)-(2018/09/22(Sat) 23:10:50)
No88739 (ひょっとこ さん) に返信
> UTF-8 の場合には、AcquireFileNameFromUTF8Headerを使って、
> Shift_JIS の場合には、AcquireFileNameFromHeaderを使えば良い
> ということですよね?
そう単純な話でも無かったりします。

たとえば
 http://www.vb-user.net/junk/replySamples/2018.09.22.19.00/sample6.php
この URL を Internet Explorer 11 や Chrome 69 で開いてみてください。
『DSC_0063 - コピー北國新聞社社長賞.JPG』というファイル名で保存されると思います。

しかし、AcquireFileNameFromUTF8Header / AcquireFileNameFromHeader の
現在の実装だと、この文字列は得られません。
ヘッダーの破損は回避できたとしても、RFC 6266 / RFC 5987 を考慮した
正規表現にはなっていませんし、パーセントエンコーディングも処理されて
いないため、filename*= の方では無く、filename= 側の方が拾われて
『DSC_0063 - COPY.JPG』というファイル名で取得されてしまいます。


> もし、Shift_JIS で喋るサーバーから
> AcquireFileNameFromUTF8Headerを使って、取得した場合、
> 文字化けしてしまいますか?

上記を含む 7 パターンのサンプルを作ってみました。
http://www.vb-user.net/junk/replySamples/2018.09.22.19.00/sample.html

先の VB コードだけでなく、Internet Explorer、Edge、あるいはその他の
ブラウザーの結果とも比較してみてください。


> そして、.NETのWebRequest クラスだと、これらの文字コードを認識する機能はない
> ということですよね?
この場合は文字コードというよりもエンコーディングの話になるかと思いますが、
.NET のソースコードを眺めてみた感じでは、そのようなものを見つけられませんでした。
サーバーから返却される、生の Stream にアクセスする手段も見当たらず…。

比較的早い段階で、ヘッダ部が WebHeaderCollection クラスという名の
NameValueCollection へと文字列変換されてしまっており、
その前に Encoding を差し込めるようなプロパティ等は見つけられませんでした。

先のように TcpClient を使うのも低レベル実装すぎて骨が折れるので、
何か良い方法があれば良いのですけれどね。


No88741 (WebSurfer さん) に返信
> 「コピー北國新聞社社長賞」の部分のバイト列:
> 0xEF, 0xBF, 0xBD, 0x52, 0xEF, 0xBF, 0xBD, 0x73, 0xEF, 0xBF, 0xBD, 0x5B, 0xEF, 0xBF, 0xBD, 0x6B,
> 0xEF, 0xBF, 0xBD, 0xEF, 0xBF, 0xBD, 0xEF, 0xBF, 0xBD, 0x56, 0xEF, 0xBF, 0xBD, 0xEF, 0xBF, 0xBD,
> 0xEF, 0xBF, 0xBD, 0xD0, 0x8E, 0xD0, 0x92, 0xEF, 0xBF, 0xBD, 0xEF, 0xBF, 0xBD, 0xEF, 0xBF, 0xBD

Fiddler をお使いなのであれば、恐らくは
Inspectors - HexView タブで確認されたのだと思いますが、
それだと Header 部に関しては化けてしまう可能性がありますので、
Inspectors - Raw タブで開いてファイルにエクスポートし、
そのファイルをバイナリエディタで確認した方が確実だったりします。


それはさておき上記では、EF,BF,BD すなわち ChrW(&HFFFD) が大量に出てきていますが、
実はこれ、Unicode の [U+FFFD] "REPLACEMENT CHARACTER" という文字なんですよね。
https://www.jpcert.or.jp/java-rules/ids11-j.html

これはつまり、下記で取得される文字と同じものです。
Dim c = DirectCast(System.Text.Encoding.UTF8.EncoderFallback, System.Text.EncoderReplacementFallback).DefaultString


このことから、テキストをバイナリとして読み取った場合に、
EF,BF,BD が多数現れるなら、UTF-8 として誤読したことによる破損
FD,FF が多数現れるなら、UTF-16 として誤読したことによる破損
FF,FD が多数現れるなら、UTF-16(BE) として誤読したことによる破損
であると予測することができます。


No88743 (ひょっとこ さん) に返信
> IE11のUser-Agentは
> Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko
> なのでしょうか?

当方環境だと、タッチパネル搭載機なので
Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko
になりますけれどね。


Internet Explorer をお使いなら、まずは [F12] キーを押して
開発者ツールを起動してみてください。
(キーボードに F12 キーが無い場合は、ツールバーの歯車アイコン)

そこから[ネットワーク]タブを開いた状態で、
適当なページを表示(あるいはリロード)してみてください。

すると、アクセスされた URL が列挙されますので、それをクリックすると
右側に表示される[ヘッダー]タブの「要求ヘッダー」部から、
User-Agent を簡単に確認することができます。

同様に [エミュレーション] タブの「ユーザーエージェント文字列」ボックスを
用いることで、IE 以外のブラウザに偽装させることもできます。

User-Agent をまとめているサイトも幾つかありますので、探してみてください。
http://utaukitune.ldblog.jp/archives/65696057.html


最近のブラウザーは、F12 キーで開発者ツールを呼び出せるものが多いので、
覚えておくと便利かと思います。


> を追加してみましたが、やはり文字化けしてしまいます。
そりゃまぁ、文字化けを防ぐための施策として説明したわけでは無いですし。(^^;

なぜ化けてしまうかの仕組みについて、それなりに詳しく
説明してきたつもりなのですが…かえって情報過多になってしまい、
仕組みの話と対策の話とが、区別しにくくなってしまったかも。
引用返信 編集キー/

このトピックをツリーで一括表示

次の20件>
トピック内ページ移動 / << 0 | 1 >>

管理者用

- Child Tree -