Forcer le téléchargement d'un pdf

Répondre
Pavulon
le 09/03/2008 à 11:59
Pavulon
Bonjour à tous

Sur une page.php je propose un lien pour visualiser un fichier PDF (qui fonctionne sans problème) et un lien pour forcer le téléchargement du même fichier PDF.

J'apprends PHP j'ai donc fait des recherches puis j'ai essayé ce que j'ai trouvé.

1°) - La première méthode:
<?php
//Envoyer l'en-tête d'attachement.
$header = "Content-Disposition: attachment; ";
$header .= "filename=$nomFichier\n";
header($header);
//Envoyer l'en-tête de type MIME (ici pdf).
header("Content-Type: application/pdf\n");
//Envoyer le document. Pas d'encodage magic_quotes.
set_magic_quotes_runtime(0);
readfile($path.$nomFichier);
?>


2°) - La seconde :
<?php
//Begin writing headers
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
header("Content-Description: File Transfer");

//Use the switch-generated Content-Type
header("Content-Type: application/pdf;");

//Force the download
$header="Content-Disposition: attachment; filename=".$nomFichier.";";
header($header );
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".$poids);
@readfile($path.$nomFichier);
exit();
?>


3°) - La troisième :
<?php		header('Content-Type: application/octet-stream');
header('Content-Length: '.$poids);
header('Content-disposition: attachment; filename='.$nomFichier);
header('Pragma: no-cache');
header('Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0');
header('Expires: 0');
readfile($path.$nomFichier);
exit();
?>



Puis en localhost je teste. À chaque fois, le lien propose bien de télécharger le fichier. Si j'accepte j'ai une petite fenêtre avec une barre verte de progression du téléchargement. Je retrouve bien le fichier "téléchargé" dans le répertoire du disque dur où a été défini l'enregistrement du téléchargement avec le bon nom et la bonne taille de fichier. Mais à chaque fois que je tente d'ouvrir ce fichier (dont l'original bien sûr fonctionne parfaitement), je reçois le message suivant :

"Acrobat n'a pas pu ouvrir exemple.pdf, car le type de fichier n'est pas pris en charge ou le fichier est endommagé (il a été envoyé en tant que pièce jointe et n'a pas été décodé correctement, par exemple). Pour créer un document Adobe PDF, ouvrez l'application source, puis imprimez le document vers Adobe PDF."

Par avance merci.
LA GLOBULE
le 10/03/2008 à 10:07
LA GLOBULE
Voici la technique que j'utilise :

<?php
define ('DL_BUFFER', 16384);

function download ($blob, $filename) {
$filename = ereg_replace('[\\/:\*\?"<>\|;]', '_', str_replace('&#32;', ' ', $filename));

$isIE = $isIE6 = false;

if (isset($_SERVER["HTTP_USER_AGENT"])) {
$HTTP_USER_AGENT = $_SERVER["HTTP_USER_AGENT"];

if (strstr($HTTP_USER_AGENT, 'compatible; MSIE ') !== false && strstr($HTTP_USER_AGENT, 'Opera') === false) {
$isIE = 1;
}
if (strstr($HTTP_USER_AGENT, 'compatible; MSIE 6') !== false && strstr($HTTP_USER_AGENT, 'Opera') === false) {
$isIE6 = 1;
}
}

header('Pragma: ');
header('Cache-Control: cache');

if ($isIE) {
$filename = rawurlencode($filename);
header ("Pragma: public");
header ("Cache-Control: no-store, max-age=0, no-cache, must-revalidate");
header ("Cache-Control: post-check=0, pre-check=0", false);
header ("Cache-Control: private");
header ("Content-Disposition: inline; filename=$filename");
}

header ("Content-Type: application/octet-stream; name=\"$filename\"");
header ("Content-Disposition: attachment; filename=\"$filename\"");

if ($isIE && !$isIE6) {
header ("Content-Type: application/download; name=\"$filename\"");
}
else {
header ("Content-Type: application/octet-stream; name=\"$filename\"");
}

$size = strlen($blob);

$nb = ($size/DL_BUFFER);
$reste = ($size%DL_BUFFER);
for ($a=0; $a<$nb; $a++) {
echo substr($blob, $a*DL_BUFFER, DL_BUFFER);
flush();
}

echo substr($blob, -$reste);
flush();
}
?>


- $filename : le nom que tu veux donner au fichier
- $blob : le contenu binaire du fichier (récupérable avec un file_get_contents)
Pavulon
le 11/03/2008 à 11:26
Pavulon
La globule merci de ton aide.

Le problème est résolu. En fait il ne venait pas du header envoyé.

Dans mon post j'ai mis trois méthodes, puis j'en ai essayé d'autres récupérées sur le net, forums, etc. Presqu'une dizaine ; et toujours le même message à l'arrivée.
Je me suis dit que bien que le header semble être une source de problèmes récurrente, ce dernier n'était peut-être pas en cause ici. Avec autant d'exemples différents de code, ça commençait à devenir logique ! Comme je suis débutant, que j'apprends, j'ai bien relu tout le code de la page (je m'étais inspiré du bouquin d'Olivier HEURTEL "PHP 5.2 Développer un site Web dynamique et interactif") et je voulais :

- lister les fichiers pdf d'un répertoire
- créer un lien précédé d'une image de fichier pdf pour pouvoir visualiser chaque fichier
- créer, à la suite du lien précedent, un lien sur une image de disquette pour télécharger ce même fichier.

et je n'avais pas mis action="telechargements.php" dans le formulaire... puisque je restais dans le même fichier.

Comme la visualisation de chaque fichier pdf, avec la série de premiers liens se déroulant normalement dans le navigateur en localhost, j'ai imputé le téléchargement corrompu à la formulation du header. Comme c'est la première fois que je l'utilise et qu'il est dit difficile je n'étais pas plus étonné que ça de rencontrer un problème...
Depuis ce rajout le message d'AcrobatReader a disparu et le fichier "téléchargé" en local s'ouvre correctement.

Je mets le code en entier peut-être que cela pourra aider d'autres débutants et peut-être trouveras-tu d'autres corrections à apporter.

fichier telechargements.php
<?php
//Liste des documents.
$documents = array();
$rep = opendir("./pdf");
while ($fichier = readdir($rep)){
if($fichier != "." && $fichier != ".."){
$documents[] = $fichier;
}
}
closedir($rep);
//TTT du formulaire si $_POST n'est pas vide.
if(!empty($_POST)){
//Récupérer le n° du document : prendre la clé de la première ligne de $_POST, normalement du type n_x
//n étant le n° du document.
list($numéro) = each($_POST);
//Convertir la chaîne en entier, seul le n° reste.
$numéro = (integer) $numéro;
//En déduire le nom du document.
$nomFichier = $documents[$numéro];
//Le chemin.
$path = "./pdf/";
//Sa taille.
$poids = filesize($path.$nomFichier);

header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Type: application/pdf\n");
$header="Content-Disposition: attachment; filename=".$nomFichier;
header($header);
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".$poids);
@readfile($path.$nomFichier);
exit();
}
?>
<form name="telechargements" method="post" action="telechargements.php">
<table cellspacing="0">
<tr><th colspan="2">Visualiser</th><th>Télécharger</th></tr>
<?php
foreach($documents as $numéro => $document){
echo sprintf("<tr><td>%s</td><td>%s</td><td>%s</td></tr>\n",
"<a href='./pdf/". $document ."' alt='Document PDF'><img src='./img_pres/ico/pdf20.png' /></a>",
"<a href='./pdf/". $document ."' alt='Document PDF'>".chaineTelechargement($document)." /></a>",
"<input type='image' name='$numéro' alt='Télécharger' src='./img_pres/ico/telecharger20.png'>");
}
?>
</table>
</form>
Pavulon
le 11/03/2008 à 11:28
Pavulon
Mais comment tu fais pour formater ? Mon code bien indenter devient tout plat !
LA GLOBULE
le 11/03/2008 à 11:30
LA GLOBULE
Quand tu écris un message, y'a un lien "bb-code", clic dessus (c'est écrit dans les conditions d'utilisation du forum en plus...).
etudiante64
le 09/04/2008 à 21:01
etudiante64
Pavulon j'ai le même soucis que toi, sauf que j'arrive pas à le résoudre :( et ca fait un moment qu'on y est dessus (on est un groupe de projet)
J'aurai vraiment besoin de ton aide.. donc est-ce que tu pourrais me contacter dès que tu vois ce message stp ?
Merci d'avance, en éspèrant avoir des nouvelles de toi :)

Mail : aingeru_begiralea [AT] hotmail [DOT] com
Répondre

Ecrire un message

Votre message vient d'être créé avec succès.
LoadingChargement en cours