web-dev-qa-db-fra.com

"nom" web pdf pour une meilleure sauvegarde par défaut du nom de fichier dans Acrobat?

Mon application génère des PDF pour la consommation de l'utilisateur. L'en-tête http "Content-Disposition" est défini comme mentionné ici . Ceci est défini sur "inline; filename = foo.pdf", ce qui devrait suffire à Acrobat pour donner le nom "foo.pdf" lors de la sauvegarde du fichier pdf.

Toutefois, lorsque vous cliquez sur le bouton "Enregistrer" dans Acrobat intégré au navigateur, le nom par défaut à enregistrer n’est pas ce nom de fichier, mais l’URL avec barres obliques modifiée en caractères de soulignement. Énorme et moche. Est-il possible d'affecter ce nom de fichier par défaut dans Adobe?

Il y a IS une chaîne de requête dans les URL, ce qui n'est pas négociable. Cela peut être important, mais l’ajout de "& foo =/title.pdf" à la fin de l’URL n’affecte pas le nom de fichier par défaut.

Mise à jour 2: j'ai essayé les deux

content-disposition  inline; filename=foo.pdf
Content-Type         application/pdf; filename=foo.pdf

et

content-disposition  inline; filename=foo.pdf
Content-Type         application/pdf; name=foo.pdf

(comme vérifié par Firebug) Malheureusement, ni l'un ni l'autre n'a fonctionné.

Un exemple d'URL est

/ bar/sessions/958d8a22-0/vues/1493881172/export? format = application/pdf & no-attachment = true

qui se traduit par une sauvegarde Acrobat par défaut sous le nom de fichier

http ___ localhost_bar_sessions_958d8a22-0_views_1493881172_export_format = application_pdf & no-attachment = true.pdf

Mise à jour 3: Julian Reschke apporte une perspicacité et une rigueur réelles à cette affaire. S'il vous plaît, passez au vote suivant pour sa réponse . Cela semble être cassé dans FF ( https://bugzilla.mozilla.org/show_bug.cgi?id=433613 ) et IE mais travaillez dans Opera, Safari et Chrome. http://greenbytes.de/tech/tc2231/#inlwithasciifilenamepdf

42
James Baker

Une partie du problème vient du fait que le RFC 2183 concerné ne précise pas quoi faire avec un type de disposition "inline" et un nom de fichier.

En outre, pour autant que je sache, le seul agent utilisateur qui utilise réellement le nom de fichier pour type = inline est Firefox (voir test case ).

Enfin, il n'est pas évident que l'API de plug-in rend ces informations disponibles (peut-être qu'un garçon familier avec l'API peut élaborer).

Cela étant dit, j'ai envoyé un pointeur sur cette question à une personne d'Adobe; peut-être que les bonnes personnes vont jeter un coup d'œil.

En relation: voir la tentative de clarification de Content-Disposition dans HTTP dans draft-reschke-rfc2183-in-http - il s'agit d'un début de travail en cours, les commentaires sont appréciés.

Mise à jour: j'ai ajouté un test case , ce qui semble indiquer que le plug-in Acrobat Reader n'utilise pas les en-têtes de réponse (dans Firefox), bien que l'API de plug-in leur donne accès.

10
Julian Reschke

Définissez également le nom de fichier dans ContentType. Cela devrait résoudre le problème.

context.Response.ContentType = "application/pdf; name=" + fileName;
// the usual stuff
context.Response.AddHeader("content-disposition", "inline; filename=" + fileName);

Une fois que vous avez défini l'en-tête de disposition du contenu, ajoutez-en aussi un en-tête, puis utilisez binarywrite pour diffuser le PDF.

context.Response.AddHeader("Content-Length", fileBytes.Length.ToString());
context.Response.BinaryWrite(fileBytes);
9
Vivek

Comme vous, j'ai essayé et essayé de faire en sorte que cela fonctionne. Finalement, j'ai abandonné cette idée et j'ai juste opté pour une solution de contournement. 

J'utilise ASP.NET MVC Framework. J'ai donc modifié les itinéraires de ce contrôleur/action pour m'assurer que le fichier PDF servi est la dernière partie de la partie emplacement de l'URI (avant la chaîne de requête). et passez tout le reste dans la chaîne de requête. 

Par exemple: 

Ancien URI: 

http: // serveur/app/report/showpdf? param1 = toto & param2 = barre & nom_fichier = myreport.pdf

Nouvel URI: 

http: //server/app/report/showpdf/myreport.pdf? param1 = toto & param2 = bar

L'en-tête qui en résulte ressemble exactement à ce que vous avez décrit (content-type est application/pdf, disposition en ligne, nom de fichier faisant inutilement partie de l'en-tête). Acrobat l'affiche dans la fenêtre du navigateur (pas d'enregistrement en tant que boîte de dialogue) et le nom de fichier qui est rempli automatiquement si un utilisateur clique sur le bouton Enregistrer d'Acrobat est le nom de fichier du rapport.

Quelques considérations:

Pour que les noms de fichiers aient une apparence correcte, ils ne doivent pas avoir de caractères d'échappement (c'est-à-dire, aucun espace, etc.) ... ce qui est un peu limitant. Mes noms de fichiers sont générés automatiquement dans ce cas et contenaient auparavant des espaces, qui apparaissaient sous la forme '% 20 dans le nom de fichier de la boîte de dialogue de sauvegarde résultant. Je viens de remplacer les espaces par des traits de soulignement, et cela a fonctionné.

Ce n’est en aucun cas la meilleure solution, mais cela fonctionne. Cela signifie également que vous devez disposer du nom de fichier pour en faire une partie de l'URI d'origine, ce qui pourrait perturber le flux de travail de votre programme. S'il est actuellement généré ou extrait d'une base de données lors de l'appel côté serveur qui génère le PDF, vous devrez peut-être déplacer le code qui génère le nom de fichier vers javascript dans le cadre de la soumission d'un formulaire ou s'il provient d'une base de données. appel ajax rapide pour obtenir le nom du fichier lors de la création de l'URL qui génère le fichier PDF incorporé.

Si vous prenez le nom de fichier d'une entrée utilisateur dans un formulaire, cela devrait être validé pour ne pas contenir de caractères d'échappement, ce qui gênerait les utilisateurs.

J'espère que cela pourra aider.

9
Troy Howard

Essayez de placer le nom du fichier à la fin de l'URL, avant tout autre paramètre. Cela a fonctionné pour moi . http://www.setasign.de/support/tips-and-tricks/filename-in-browser-plugin/

5
tekkgurrl

mod_rewrite d'Apache peut résoudre ce problème.

J'ai un service Web avec un terminal à /foo/getDoc.service. Bien entendu, Acrobat enregistrera les fichiers sous le nom getDoc.pdf. J'ai ajouté les lignes suivantes dans Apache.conf:

LoadModule     RewriteModule         modules/mod_rewrite.so
RewriteEngine  on
RewriteRule    ^/foo/getDoc/(.*)$    /foo/getDoc.service     [P,NE]

Désormais, lorsque je demande /foo/getDoc/filename.pdf?bar&qux, il est réécrit en interne sur /foo/getDoc.service?bar&qux. Je sélectionne donc le noeud final approprié du service Web, mais Acrobat pense que le fichier sera enregistré sous le nom filename.pdf.

4
Mark Nettle

Dans ASP.NET 2.0, changez l’URL de 

http://www. server.com/DocServe.aspx?DocId=XXXXXXX

à 

http://www. server.com/DocServe.aspx/MySaveAsFileName?DocId=XXXXXXX

Cela fonctionne pour Acrobat 8 ​​et le nom de fichier SaveAs par défaut est maintenant MySaveAsFileName.pdf

Cependant, vous devez restreindre les caractères autorisés dans MySaveAsFileName (pas de points, etc.).

4
Karsten

Si vous utilisez asp.net, vous pouvez contrôler le nom de fichier pdf à l'aide du nom de fichier page (url) . Comme d'autres utilisateurs l'ont écrit, Acrobat est un peu s ... lorsqu'il choisit le nom du fichier pdf lorsque vous appuyez sur le bouton "Enregistrer" : il prend le nom de la page, supprime l’extension et ajoute ".pdf". So /foo/bar/GetMyPdf.aspx donne GetMyPdf.pdf.

La seule solution que j'ai trouvée consiste à gérer les noms de page "dynamiques" via un gestionnaire asp.net: 

  • créer une classe qui implémente IHttpHandler 
  • mapper un gestionnaire dans web.config lié à la classe

Mapping1: toutes les pages ont une base commune (MyDocument_):

<httpHandlers>  
<add verb="*" path="MyDocument_*.ashx" type="ITextMiscWeb.MyDocumentHandler"/>

Mapping2: nom de fichier complètement libre (besoin d'un dossier dans le chemin): 

<add verb="*" path="/CustomName/*.ashx" type="ITextMiscWeb.MyDocumentHandler"/>

Quelques astuces ici (le pdf est créé dynamiquement avec iTextSharp):
http://fhtino.blogspot.com/2006/11/how-to-show-or-download-pdf-file-from.html

2

Au lieu de la pièce jointe, vous pouvez essayer en ligne:

Response.AddHeader("content-disposition", "inline;filename=MyFile.pdf");

J'utilise inline dans une application Web précédente qui génère une sortie Crystal Reports dans PDF et l'envoie dans le navigateur à l'utilisateur.

1
ManiacZX

Je crois que cela a déjà été mentionné dans une saveur ou une autre, mais je vais essayer de l'exprimer avec mes propres mots.

Plutôt que cela:

/bar/sessions/958d8a22-0/views/1493881172/export?format=application/pdf&no-attachment=true

J'utilise ceci:

/bar/sessions/958d8a22-0/views/1493881172/NameThatIWantPDFToBe.pdf?GeneratePDF=1

Plutôt que de faire "exporter" la requête, lorsqu'une requête arrive, je cherche dans l'URL GeneratePDF = 1. S'il est trouvé, j'exécute le code utilisé dans "export" plutôt que de permettre à mon système de rechercher et de servir un PDF à l'emplacement /bar/sessions/958d8a22-0/views/1493881172/NameThatIWantPDFToBe.pdf. Si GeneratePDF n'est pas trouvé dans l'URL, je transmets simplement le fichier demandé. (notez que je ne peux pas simplement rediriger vers le fichier demandé - sinon je finirais dans une boucle sans fin)

1
Matt

Boîte de dialogue de téléchargement de fichier (PDF) avec option d'enregistrement et d'ouverture

Points à retenir:

  1. Renvoyer le flux avec la taille de matrice correcte du service
  2. Lisez l'octet arrary du flux avec la longueur d'octet correcte sur la base de la longueur du flux.
  3. définir le type de contenu correct

Voici le code pour lire le flux et ouvrir la boîte de dialogue de téléchargement de fichier pour le fichier 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();
    }
}
1
Sunder Chhokar

J'ai été redirigé ici parce que j'ai le même problème. J'ai aussi essayé la solution de contournement de Troy Howard mais cela ne semble pas fonctionner.

L'approche que j'ai faite sur celui-ci consiste à NE PLUS utiliser d'objet de réponse pour écrire le fichier à la volée. Comme le PDF existe déjà sur le serveur, ce que j'ai fait est de rediriger ma page vers ce fichier PDF. Fonctionne très bien.

http://forums.asp.net/t/143631.aspx

J'espère que mes explications vagues vous ont donné une idée.

0
mark

Vous pouvez toujours avoir deux liens. Un qui ouvre le document dans le navigateur et un autre pour le télécharger (avec un type de contenu incorrect). C’est ce que fait Gmail.

0
Vincent McNabb

Pour ceux qui regardent encore cela, j'ai utilisé la solution trouvée ici et cela a fonctionné à merveille. Merci Fabrizio!

0
Brian

La façon dont j'ai résolu ce problème (avec PHP) est la suivante:

Supposons que votre URL est SomeScript.php?id=ID&data=DATA et que le fichier que vous souhaitez utiliser est TEST.pdf.

Modifiez l'URL en SomeScript.php/id/ID/data/DATA/EXT/TEST.pdf.

Il est important que le dernier paramètre soit le nom de fichier que vous souhaitez que Adobe utilise (le "EXT" peut concerner n'importe quoi). Assurez-vous qu'il n'y a pas de caractères spéciaux dans la chaîne ci-dessus, BTW.

Maintenant, en haut de SomeScript.php, ajoutez:

$_REQUEST = MakeFriendlyURI( $_SERVER['PHP\_SELF'], $_SERVER['SCRIPT_FILENAME']);

Ajoutez ensuite cette fonction à SomeScript.php (ou votre bibliothèque de fonctions):

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 $_REQUEST or $_GET
 */
for ($i=0;$i < count($tmp); $i = $i+2){
    $RequestArray[$tmp[$i]] = $tmp[$i+1];
}
return $RequestArray;       
}//EO MakeFriendlyURI

Maintenant, $_REQUEST (ou $_GET si vous préférez) est utilisé comme d'habitude $_REQUEST['id'], $_REQUEST['data'], etc.

De plus, Adobe utilisera le nom de fichier souhaité comme nom par défaut, soit enregistrer sous ou par courrier électronique, lorsque vous l'enverrez en ligne.

0
Rick Cooper

Crédits à 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;
}

Vérifier avec

curl -I https://example.com/file.pdf

Firefox 62.0b5 (64 bits): OK.

Chrome 67.0.3396.99 (64 bits): OK.

IE 11: Pas de commentaire.

0
qräbnö