Page 1 sur 1

Forcer le téléchargement PDF

Posté : 09 mars 2008, 13:14
par 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:
//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.

Posté : 09 mars 2008, 13:43
par Cyrano
As-tu regardé ceci ?

Posté : 09 mars 2008, 15:29
par Ryle
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.

Message erreur sur téléchargement

Posté : 09 mars 2008, 17:48
par Pavulon
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.

Download pdf et message d'erreur

Posté : 11 mars 2008, 13:00
par Pavulon
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.