Forcer le téléchargement PDF

Petit nouveau ! | 3 Messages

09 mars 2008, 13:14

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:
//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 :
//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 :
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.

Mammouth du PHP | 19672 Messages

09 mars 2008, 13:43

As-tu regardé ceci ?
Codez en pensant que celui qui maintiendra votre code est un psychopathe qui connait votre adresse :axe:

Avatar du membre
Modérateur PHPfrance
Modérateur PHPfrance | 10684 Messages

09 mars 2008, 15:29

Modération :
Pavulon, afin d'améliorer la lisibilité de ton message,
pense à utiliser les balises [code] ou [php] (selon le langage utilisé).

Elles sont disponibles au-dessus de la zone de saisie de ton message
lorsque tu postes un nouveau message.

Des indications sont disponibles sur la manière de mettre en forme vos messages dans la FAQ


Par ailleurs, comme le fait remarquer Cyrano et puisque tu seras dans la FAQ, tu découvriras
que ce sujet a déjà été traité et des réponses ont été apportées.
Faire une petite recherche préalable n'est pas superflu.
Ce n'est pas en améliorant la bougie que l'on a inventé l'ampoule...

Petit nouveau ! | 3 Messages

09 mars 2008, 17:48

Ah oui, mille excuses Ryle. Les boutons sont pourtant bien visibles.

Oui Cyrano, j'ai aussi testé ceci ; comme cela.
    header('Content-Type: application/octet-stream'); 
    header('Content-Disposition: attachment; filename='.$nomFichier); 
    header('Accept-Ranges: bytes'); 
    header('Content-Length: '.$poids); 
    readfile($path.$nomFichier);
Je "télécharge" aussi bien avec ces 5 lignes, mais j'ai toujours le même message à l'arrivée.

J'ai fait des recherches ici et ailleurs mais je ne rencontre ce problème nulle part. Partout on demande comment forcer le téléchargement ; ou de tels ou tels types de fichiers ; ou le fichier arrive avec une taille nulle ou perd son nom, etc. Mais pas ce problème...

Je suis en localhost sous XP Pro, WampServer (Apache 2.2.6, PHP 5.2.5).

Merci.

Petit nouveau ! | 3 Messages

11 mars 2008, 13:00

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...

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>
Merci à tous.