Acrobat でのデフォルトの保存ファイル名を改善するには、「name」Web PDF を使用しますか?
-
02-07-2019 - |
質問
私のアプリはユーザーが使用できる PDF を生成します。「Content-Disposition」http ヘッダーは前述のように設定されます ここ. 。これは「インライン;」に設定されます。filename=foo.pdf」。これは、Acrobat が PDF を保存するときにファイル名として「foo.pdf」を指定するのに十分なはずです。
ただし、ブラウザに埋め込まれた Acrobat で [保存] ボタンをクリックすると、保存されるデフォルトの名前はそのファイル名ではなく、スラッシュがアンダースコアに変更された URL になります。巨大で醜い。Adobe でこのデフォルトのファイル名に影響を与える方法はありますか?
URL にはクエリ文字列があり、これは交渉の余地がありません。これは重要かもしれませんが、URL の末尾に「&foo=/title.pdf」を追加しても、デフォルトのファイル名には影響しません。
アップデート 2:両方試してみました
content-disposition inline; filename=foo.pdf
Content-Type application/pdf; filename=foo.pdf
そして
content-disposition inline; filename=foo.pdf
Content-Type application/pdf; name=foo.pdf
(Firebug で確認済み) 残念ながら、どちらも機能しませんでした。
サンプルURLは
/bar/sessions/958d8a22-0/views/1493881172/export?format=application/pdf&no-attachment=true
これは、デフォルトの Acrobat のファイル名として変換されます。
http___localhost_bar_sessions_958d8a22-0_views_1493881172_export_format=application_pdf&no-attachment=true.pdf
アップデート 3:ジュリアン・レシュケは、この事件に実際の洞察と厳密さをもたらします。彼の答えに賛成票を投じてください。これはFFでは壊れているようです(https://bugzilla.mozilla.org/show_bug.cgi?id=433613) と IE ですが、Opera、Safari、Chrome でも動作します。 http://greenbytes.de/tech/tc2231/#inlwithasciiファイル名pdf
解決
問題の一部は、関連する RFC 2183 が実際には何を述べていないかです「インライン」の処理タイプを処理するにはファイル名。
また、私が知る限り、type = inlineのファイル名を実際に使用するUAはFirefoxのみです(テストケース)。
最後に、プラグインAPIが実際にその情報を利用可能にするかどうかは明らかではありません(おそらく、APIに精通している誰かが詳しく説明できるでしょう)。
そうは言っても、私はこの質問へのポインタをアドビの人に送った。たぶん、適切な人が見ているでしょう。
関連: draft-reschke-rfc2183-in-http -これは初期の作業であり、フィードバックをお待ちしています。
更新:テストケースを追加しました。これはAcrobat Readerを示しているようですプラグインAPIはレスポンスヘッダーへのアクセスを提供しますが、プラグインはレスポンスヘッダーを使用しません(Firefoxで)。
他のヒント
ContentType にもファイル名を設定します。これで問題が解決するはずです。
context.Response.ContentType = "application/pdf; name=" + fileName;
// the usual stuff
context.Response.AddHeader("content-disposition", "inline; filename=" + fileName);
content-dispositionヘッダーを設定したら、content-lengthヘッダーも追加し、binarywriteを使用してPDFをストリーミングします。
context.Response.AddHeader("Content-Length", fileBytes.Length.ToString());
context.Response.BinaryWrite(fileBytes);
あなたと同じように、私はこれを機能させようとしました。最後に、私はこの考えをあきらめ、回避策を選んだ。
ASP.NET MVCフレームワークを使用しているため、そのコントローラー/アクションのルートを変更して、提供されるPDFファイルがURIの場所部分の最後の部分(クエリ文字列の前)になるようにしました。クエリ文字列で他のすべてを渡します。
例:
古いURI:
http:// server / app / report / showpdf?param1 = foo& param2 = bar& filename = myreport.pdf
新しいURI:
http:// server / app / report / showpdf / myreport。 pdf?param1 = foo& param2 = bar
結果のヘッダーは、説明したとおりになります(content-typeはapplication / pdf、dispositionはインライン、filenameは無駄なヘッダーの一部です)。 Acrobatはブラウザウィンドウに表示し(ダイアログとして保存しない)、ユーザーがAcrobatの[保存]ボタンをクリックすると自動入力されるファイル名がレポートファイル名です。
いくつかの考慮事項:
ファイル名が適切に見えるようにするには、エスケープ文字を使用しないでください(スペースがないなど)。これは少し制限されています。この場合、私のファイル名は自動生成され、以前はスペースが含まれていたため、結果の保存ダイアログのファイル名に「%20」として表示されていました。スペースをアンダースコアに置き換えたところ、うまくいきました。
これは最善の解決策ではありませんが、機能します。また、元のURIの一部にするためにファイル名を使用できるようにする必要があることを意味します。これは、プログラムのワークフローを混乱させる可能性があります。 PDFを生成するサーバー側の呼び出し中にデータベースから現在生成または取得されている場合、フォーム送信の一部としてファイル名を生成するコードをjavascriptに移動するか、データベースから取得する場合はインラインPDFを生成するURLを作成するときにファイル名を取得するためのクイックajax呼び出し。
フォーム上のユーザー入力からファイル名を取得している場合、エスケープ文字が含まれていないことを検証する必要があります。これはユーザーを悩ますでしょう。
役立つこと。
他のパラメータの前に、URLの最後にファイル名を配置してみてください。これは私のために働いた。 http://www.setasign.de/support/ tips-and-tricks / filename-in-browser-plugin /
ASP.NET 2.0 では、URL を次から変更します。
http://www. server.com/DocServe.aspx?DocId=XXXXXXX
に
http://www. server.com/DocServe.aspx/MySaveAsFileName?DocId=XXXXXXX
これは Acrobat 8 で機能し、デフォルトの名前を付けて保存のファイル名は次のようになります。 MySaveAsFileName.pdf
.
ただし、使用できる文字を制限する必要があります。 MySaveAsFileName
(ピリオドなどはありません)。
Apacheの mod_rewrite
はこれを解決できます。
/foo/getDoc.service
にエンドポイントを持つWebサービスがあります。もちろん、Acrobatは getDoc.pdf
としてファイルを保存します。 apache.conf
に次の行を追加しました:
LoadModule RewriteModule modules/mod_rewrite.so
RewriteEngine on
RewriteRule ^/foo/getDoc/(.*)$ /foo/getDoc.service [P,NE]
今 /foo/getDoc/filename.pdf?bar&qux
をリクエストすると、内部的に /foo/getDoc.service?bar&qux
に書き換えられます。そのため、Webサービスの正しいエンドポイントにアクセスしていますが、Acrobatはファイルを filename.pdf
として保存すると考えています。
asp.netを使用する場合、ページ(url)ファイル名を使用してpdfファイル名を制御できます。 他のユーザーが書いたように、Acrobatは、「保存」を押したときにPDFファイル名を選択するときに少し便利です。ボタン:ページ名を取得し、拡張子を削除して「.pdf」を追加します。 /foo/bar/GetMyPdf.aspxはGetMyPdf.pdfを提供します。
私が見つけた唯一の解決策は、「動的」を管理することです。 asp.netハンドラーを介したページ名:
- IHttpHandlerを実装するクラスを作成します
- クラスにバインドされたweb.configのハンドラーをマッピングする
マッピング1:すべてのページに共通の基数(MyDocument_)があります:
<httpHandlers>
<add verb="*" path="MyDocument_*.ashx" type="ITextMiscWeb.MyDocumentHandler"/>
マッピング2:完全に自由なファイル名(パスにフォルダーが必要):
<add verb="*" path="/CustomName/*.ashx" type="ITextMiscWeb.MyDocumentHandler"/>
ここでのヒント(pdfはiTextSharpを使用して動的に作成されます):
http:// fhtino。 blogspot.com/2006/11/how-to-show-or-download-pdf-file-from.html
添付ファイルの代わりにインラインで試すことができます:
Response.AddHeader("content-disposition", "inline;filename=MyFile.pdf");
Crystal Reports出力をPDFに生成し、それをブラウザでユーザーに送信する以前のWebアプリケーションでインラインを使用しました。
保存および開くオプションを使用したファイルダウンロードダイアログ(PDF)
覚えておくべきポイント:
- サービスから正しい配列サイズでストリームを返す
- ストリームの長さに基づいて、正しいバイト長でストリームからバイト配列を読み取ります。
- 正しいcontenttypeを設定
ストリームを読み取り、PDFファイルのファイルダウンロードダイアログを開くためのコードは次のとおりです
private void DownloadSharePointDocument()
{
Uri uriAddress = new Uri("http://hyddlf5187:900/SharePointDownloadService/FulfillmentDownload.svc/GetDocumentByID/1/drmfree/");
HttpWebRequest req = WebRequest.Create(uriAddress) as HttpWebRequest;
// Get response
using (HttpWebResponse httpWebResponse = req.GetResponse() as HttpWebResponse)
{
Stream stream = httpWebResponse.GetResponseStream();
int byteCount = Convert.ToInt32(httpWebResponse.ContentLength);
byte[] Buffer1 = new byte[byteCount];
using (BinaryReader reader = new BinaryReader(stream))
{
Buffer1 = reader.ReadBytes(byteCount);
}
Response.Clear();
Response.ClearHeaders();
// set the content type to PDF
Response.ContentType = "application/pdf";
Response.AddHeader("Content-Disposition", "attachment;filename=Filename.pdf");
Response.Buffer = true;
Response.BinaryWrite(Buffer1);
Response.Flush();
// Response.End();
}
}
これはすでに何らかのフレーバーで言及されていると思いますが、私は自分の言葉でそれを説明しようとします。
これよりも:
/bar/sessions/958d8a22-0/views/1493881172/export?format=application/pdf&no-attachment=true
これを使用:
/bar/sessions/958d8a22-0/views/1493881172/NameThatIWantPDFToBe.pdf?GeneratePDF=1
「エクスポート」するのではなく、リクエストを処理し、リクエストが来たら、GeneratePDF = 1のURLを調べます。見つかった場合、&quot; export&quot;で実行されていたコードを実行します。私のシステムが /bar/sessions/958d8a22-0/views/1493881172/NameThatIWantPDFToBe.pdf
の場所でPDFの検索と提供を試みることを許可するのではありません。 GeneratePDFがURLで見つからない場合、要求されたファイルを送信するだけです。 (要求されたファイルに単純にリダイレクトできないことに注意してください-さもないと、無限ループになってしまいます)
常に2つのリンクを使用できます。 1つはブラウザ内でドキュメントを開き、もう1つはそれをダウンロードします(間違ったコンテンツタイプを使用)。これがGmailの機能です。
まだこれを見ている人のために、こちらで見つかったソリューションを使用しました素晴らしかった。ファブリツィオに感謝します!
これを(PHPで)解決した方法は次のとおりです。
URLが SomeScript.php?id = ID&amp; data = DATA
で、使用するファイルが TEST.pdf
であるとします。
URLを SomeScript.php / id / ID / data / DATA / EXT / TEST.pdf
に変更します。
最後のパラメーターは、アドビが使用するファイル名であることが重要です(「EXT」には任意の名前を指定できます)。上記の文字列BTWに特別な文字がないことを確認してください。
今、 SomeScript.php
の上部に、以下を追加します。
これを(PHPで)解決した方法は次のとおりです。
URLが SomeScript.php?id = ID&amp; data = DATA
で、使用するファイルが TEST.pdf
であるとします。
URLを SomeScript.php / id / ID / data / DATA / EXT / TEST.pdf
に変更します。
最後のパラメーターは、アドビが使用するファイル名であることが重要です(「EXT」には任意の名前を指定できます)。上記の文字列BTWに特別な文字がないことを確認してください。
今、 SomeScript.php
の上部に、以下を追加します。
function MakeFriendlyURI($URI, $ScriptName) {
/* Need to remove everything up to the script name */
$MyName = '/^.*'.preg_quote(basename($ScriptName)."/", '/').'/';
$Str = preg_replace($MyName,'',$URI);
$RequestArray = array();
/* Breaks down like this
0 1 2 3 4 5
PARAM1/VAL1/PARAM2/VAL2/PARAM3/VAL3
*/
$tmp = explode('/',$Str);
/* Ok so build an associative array with Key->value
This way it can be returned back to これを(PHPで)解決した方法は次のとおりです。
URLが SomeScript.php?id = ID&amp; data = DATA
で、使用するファイルが TEST.pdf
であるとします。
URLを SomeScript.php / id / ID / data / DATA / EXT / TEST.pdf
に変更します。
最後のパラメーターは、アドビが使用するファイル名であることが重要です(「EXT」には任意の名前を指定できます)。上記の文字列BTWに特別な文字がないことを確認してください。
今、 SomeScript.php
の上部に、以下を追加します。
これを(PHPで)解決した方法は次のとおりです。
URLが SomeScript.php?id = ID&amp; data = DATA
で、使用するファイルが TEST.pdf
であるとします。
URLを SomeScript.php / id / ID / data / DATA / EXT / TEST.pdf
に変更します。
最後のパラメーターは、アドビが使用するファイル名であることが重要です(「EXT」には任意の名前を指定できます)。上記の文字列BTWに特別な文字がないことを確認してください。
今、 SomeScript.php
の上部に、以下を追加します。
<*>
次に、この関数を SomeScript.php
(または関数ライブラリ)に追加します:
<*>
Now $ _ REQUEST
(または必要に応じて $ _ GET
)は通常の $ _ REQUEST ['id']
、のようにアクセスされます$ _REQUEST ['data']
など。
また、アドビは、希望するファイル名をデフォルトの名前を付けて保存するか、インラインで送信するときにメール情報を使用します。
REQUEST = MakeFriendlyURI( これを(PHPで)解決した方法は次のとおりです。
URLが SomeScript.php?id = ID&amp; data = DATA
で、使用するファイルが TEST.pdf
であるとします。
URLを SomeScript.php / id / ID / data / DATA / EXT / TEST.pdf
に変更します。
最後のパラメーターは、アドビが使用するファイル名であることが重要です(「EXT」には任意の名前を指定できます)。上記の文字列BTWに特別な文字がないことを確認してください。
今、 SomeScript.php
の上部に、以下を追加します。
<*>
次に、この関数を SomeScript.php
(または関数ライブラリ)に追加します:
<*>
Now $ _ REQUEST
(または必要に応じて $ _ GET
)は通常の $ _ REQUEST ['id']
、のようにアクセスされます$ _REQUEST ['data']
など。
また、アドビは、希望するファイル名をデフォルトの名前を付けて保存するか、インラインで送信するときにメール情報を使用します。
SERVER['PHP\_SELF'], これを(PHPで)解決した方法は次のとおりです。
URLが SomeScript.php?id = ID&amp; data = DATA
で、使用するファイルが TEST.pdf
であるとします。
URLを SomeScript.php / id / ID / data / DATA / EXT / TEST.pdf
に変更します。
最後のパラメーターは、アドビが使用するファイル名であることが重要です(「EXT」には任意の名前を指定できます)。上記の文字列BTWに特別な文字がないことを確認してください。
今、 SomeScript.php
の上部に、以下を追加します。
<*>
次に、この関数を SomeScript.php
(または関数ライブラリ)に追加します:
<*>
Now $ _ REQUEST
(または必要に応じて $ _ GET
)は通常の $ _ REQUEST ['id']
、のようにアクセスされます$ _REQUEST ['data']
など。
また、アドビは、希望するファイル名をデフォルトの名前を付けて保存するか、インラインで送信するときにメール情報を使用します。
SERVER['SCRIPT_FILENAME']);
次に、この関数を SomeScript.php
(または関数ライブラリ)に追加します:
<*>
Now $ _ REQUEST
(または必要に応じて $ _ GET
)は通常の $ _ REQUEST ['id']
、のようにアクセスされます$ _REQUEST ['data']
など。
また、アドビは、希望するファイル名をデフォルトの名前を付けて保存するか、インラインで送信するときにメール情報を使用します。
REQUEST or これを(PHPで)解決した方法は次のとおりです。
URLが SomeScript.php?id = ID&amp; data = DATA
で、使用するファイルが TEST.pdf
であるとします。
URLを SomeScript.php / id / ID / data / DATA / EXT / TEST.pdf
に変更します。
最後のパラメーターは、アドビが使用するファイル名であることが重要です(「EXT」には任意の名前を指定できます)。上記の文字列BTWに特別な文字がないことを確認してください。
今、 SomeScript.php
の上部に、以下を追加します。
これを(PHPで)解決した方法は次のとおりです。
URLが SomeScript.php?id = ID&amp; data = DATA
で、使用するファイルが TEST.pdf
であるとします。
URLを SomeScript.php / id / ID / data / DATA / EXT / TEST.pdf
に変更します。
最後のパラメーターは、アドビが使用するファイル名であることが重要です(「EXT」には任意の名前を指定できます)。上記の文字列BTWに特別な文字がないことを確認してください。
今、 SomeScript.php
の上部に、以下を追加します。
<*>
次に、この関数を SomeScript.php
(または関数ライブラリ)に追加します:
<*>
Now $ _ REQUEST
(または必要に応じて $ _ GET
)は通常の $ _ REQUEST ['id']
、のようにアクセスされます$ _REQUEST ['data']
など。
また、アドビは、希望するファイル名をデフォルトの名前を付けて保存するか、インラインで送信するときにメール情報を使用します。
REQUEST = MakeFriendlyURI( これを(PHPで)解決した方法は次のとおりです。
URLが SomeScript.php?id = ID&amp; data = DATA
で、使用するファイルが TEST.pdf
であるとします。
URLを SomeScript.php / id / ID / data / DATA / EXT / TEST.pdf
に変更します。
最後のパラメーターは、アドビが使用するファイル名であることが重要です(「EXT」には任意の名前を指定できます)。上記の文字列BTWに特別な文字がないことを確認してください。
今、 SomeScript.php
の上部に、以下を追加します。
<*>
次に、この関数を SomeScript.php
(または関数ライブラリ)に追加します:
<*>
Now $ _ REQUEST
(または必要に応じて $ _ GET
)は通常の $ _ REQUEST ['id']
、のようにアクセスされます$ _REQUEST ['data']
など。
また、アドビは、希望するファイル名をデフォルトの名前を付けて保存するか、インラインで送信するときにメール情報を使用します。
SERVER['PHP\_SELF'], これを(PHPで)解決した方法は次のとおりです。
URLが SomeScript.php?id = ID&amp; data = DATA
で、使用するファイルが TEST.pdf
であるとします。
URLを SomeScript.php / id / ID / data / DATA / EXT / TEST.pdf
に変更します。
最後のパラメーターは、アドビが使用するファイル名であることが重要です(「EXT」には任意の名前を指定できます)。上記の文字列BTWに特別な文字がないことを確認してください。
今、 SomeScript.php
の上部に、以下を追加します。
<*>
次に、この関数を SomeScript.php
(または関数ライブラリ)に追加します:
<*>
Now $ _ REQUEST
(または必要に応じて $ _ GET
)は通常の $ _ REQUEST ['id']
、のようにアクセスされます$ _REQUEST ['data']
など。
また、アドビは、希望するファイル名をデフォルトの名前を付けて保存するか、インラインで送信するときにメール情報を使用します。
SERVER['SCRIPT_FILENAME']);
次に、この関数を SomeScript.php
(または関数ライブラリ)に追加します:
<*>
Now $ _ REQUEST
(または必要に応じて $ _ GET
)は通常の $ _ REQUEST ['id']
、のようにアクセスされます$ _REQUEST ['data']
など。
また、アドビは、希望するファイル名をデフォルトの名前を付けて保存するか、インラインで送信するときにメール情報を使用します。
GET
*/
for ($i=0;$i < count($tmp); $i = $i+2){
$RequestArray[$tmp[$i]] = $tmp[$i+1];
}
return $RequestArray;
}//EO MakeFriendlyURI
次に、この関数を SomeScript.php
(または関数ライブラリ)に追加します:
<*>
Now $ _ REQUEST
(または必要に応じて $ _ GET
)は通常の $ _ REQUEST ['id']
、のようにアクセスされます$ _REQUEST ['data']
など。
また、アドビは、希望するファイル名をデフォルトの名前を付けて保存するか、インラインで送信するときにメール情報を使用します。
REQUEST = MakeFriendlyURI( これを(PHPで)解決した方法は次のとおりです。
URLが SomeScript.php?id = ID&amp; data = DATA
で、使用するファイルが TEST.pdf
であるとします。
URLを SomeScript.php / id / ID / data / DATA / EXT / TEST.pdf
に変更します。
最後のパラメーターは、アドビが使用するファイル名であることが重要です(「EXT」には任意の名前を指定できます)。上記の文字列BTWに特別な文字がないことを確認してください。
今、 SomeScript.php
の上部に、以下を追加します。
<*>
次に、この関数を SomeScript.php
(または関数ライブラリ)に追加します:
<*>
Now $ _ REQUEST
(または必要に応じて $ _ GET
)は通常の $ _ REQUEST ['id']
、のようにアクセスされます$ _REQUEST ['data']
など。
また、アドビは、希望するファイル名をデフォルトの名前を付けて保存するか、インラインで送信するときにメール情報を使用します。
SERVER['PHP\_SELF'], これを(PHPで)解決した方法は次のとおりです。
URLが SomeScript.php?id = ID&amp; data = DATA
で、使用するファイルが TEST.pdf
であるとします。
URLを SomeScript.php / id / ID / data / DATA / EXT / TEST.pdf
に変更します。
最後のパラメーターは、アドビが使用するファイル名であることが重要です(「EXT」には任意の名前を指定できます)。上記の文字列BTWに特別な文字がないことを確認してください。
今、 SomeScript.php
の上部に、以下を追加します。
<*>
次に、この関数を SomeScript.php
(または関数ライブラリ)に追加します:
<*>
Now $ _ REQUEST
(または必要に応じて $ _ GET
)は通常の $ _ REQUEST ['id']
、のようにアクセスされます$ _REQUEST ['data']
など。
また、アドビは、希望するファイル名をデフォルトの名前を付けて保存するか、インラインで送信するときにメール情報を使用します。
SERVER['SCRIPT_FILENAME']);
次に、この関数を SomeScript.php
(または関数ライブラリ)に追加します:
Now $ _ REQUEST
(または必要に応じて $ _ GET
)は通常の $ _ REQUEST ['id']
、のようにアクセスされます$ _REQUEST ['data']
など。
また、アドビは、希望するファイル名をデフォルトの名前を付けて保存するか、インラインで送信するときにメール情報を使用します。
同じ問題があるため、ここにリダイレクトされました。トロイハワードの回避策も試しましたが、うまくいかないようです。
私がこの方法で行ったアプローチは、応答オブジェクトを使用してファイルをその場で書き込むことはもうありません。 PDFはサーバー上に既に存在するため、私がしたことは、そのPDFファイルを指すページをリダイレクトすることでした。すばらしい。
http://forums.asp.net/t/143631.aspx
曖昧な説明があなたにアイデアを与えてくれたことを願っています。
Vivek へのクレジット。
Nginx
location /file.pdf
{
# more_set_headers "Content-Type: application/pdf; name=save_as_file.pdf";
add_header Content-Disposition "inline; filename=save_as_file.pdf";
alias /var/www/file.pdf;
}
確認
curl -I https://example.com/file.pdf
Firefox 62.0b5(64ビット):OK。
Chrome 67.0.3396.99(64ビット):OK。
IE 11:コメントなし。
実行可能ファイルが&quot; get.cgi&quot;の場合、これを試してください
http://server,org/get.cgi/filename .pdf?file = filename.pdf
はい、それは完全に狂っています。 &quot; filename.pdf&quot;というファイルはありません。サーバーでは、実行可能get.cgiの下にディレクトリがあります。
しかし、うまくいくようです。サーバーはfilename.pdfを無視し、pdfリーダーは&quot; get.cgi&quot;を無視します。
ダン