10 commenti apache, tutorial, php

Fornire agli utenti la possibilità di scaricare file attraverso il nostro sito web è un'operazione nel complesso semplice ma che richiede particolari accorgimenti.

 

Il modo più semplice per fare ciò prevede un normale tag <a> html con l'attributo href indicante il percorso al file.

<a href="file.zip" target="_blank">Scarica il file</a>

 

Questa tecnica è perfettamente funzionale per molte tipologie di file archivio: .zip, .tar, .gzip.

 

Al contrario, il comportamento predefinito dei browser per molte altre tipologie di file (ad esempio .pdf, .mp3, .doc) prevedono l'apertura di una nuova finestra.

Tale comportamento è possibile modificarlo inviando al browser gli opportuni headers così da far aprire la finestra del "Salva con nome" e consentire all'utente di salvarlo immediatamente sul proprio pc. In particolare l'headers in oggetto sarà:

Content-disposition: attachment;

 

Per inviare tale headers al browser possiamo impiegare due tecniche:

  1. la prima farà ricorso ad un file .htaccess;
  2. con la seconda, invece, il download del file e l'invio degli headers avverrà in modo indiretto tramite uno script php.

 

Forzare il download tramite .htaccess

In questo caso è utile collocare i file per il downaload in una cartella dedicata e al suo internoandremo a creare un file .htaccess con le seguenti istruzioni:

<FilesMatch "\.(?i:doc|xls|pdf|mp3|txt)">
  ForceType application/octet-stream
  Header set Content-Disposition attachment
</FilesMatch>

 

Così come impostato gli headers verranno modificati per i file con estensione doc, xls, pdf, mp3 e txt (ovviamente potete modificarlo a vostro piacimento eliminando i presenti o inserendone di nuovi).

A questo punto il semplice link come quello precedentemente descirtto (il tag <a>) ad uno di essi farà aprire la finestra del download secondo le specifiche dei vari browser.

 

Impostare gli header per il download con Php

Con la seconda tecnica il download del file avverrà attraverso un file php che farà da "filtro".

Ecco di seguito un codice di esempio di un file che chiameremo, ad esempio download.php:

<?php  
/*  
impostiamo la cartella in cui sono presenti  
i file per il download  
*/  
$dir = "download/";  
  
/*  
riceviamo via GET il file da scaricare 
la funzione basename la applichiamo al fine di evitare che  
utenti maliziosi possano eseguire percorsi nell'URL 
 */  
$file = isset($_GET['file']) ? basename( (string) $_GET['file'] ) : '';  
  
$path = $dir . $file;  

/* eseguiamo alcuni controlli preventivi */  
if($file==''){
	exit('Nessun file indicato');
	}
else if(!is_file($path)){  
    exit('Il file non esiste');  
    }  
else if(!is_readable($path)){  
    exit('Il file non ha i permessi per essere scaricato');  
    }  
    
/* otteniamo alcune info sul file */  
$info = pathinfo( $path );  
$extension = $info['extension']; // estensione  
$size = filesize($path); // dimensione in byte  
$time_file = date( 'r', filemtime( $path ) ); // time ultima modifica  
 
/* inviamo gli opportuni headers */  
/* alcuni di questi sono degli hack (trucchi)  
per farlo funzionare correttamente anche su alcune versioni di IE*/  
header('Content-Type: application/octet-stream');  
header('Content-Disposition: attachment; filename="'. basename($path) .'"');   
header('Content-Transfer-Encoding: binary');  
header('Content-Length: ' . $size);  
header('Last-Modified: ' . $time_file);  
header('Expires: 0');  
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');  
header('Pragma: public');  
    
/* eliminiamo eventuale output inviato */  
ob_clean();  
flush();  
  
/* leggiamo il file inviamo l'output */  
@readfile($path) or die('SERVER ERROR!');  
exit;  
?> 

 

A questo punto per consentire il download del file "document.pdf" faremo un link al file download.php indereno nella quesry string la variabile get "file", ovvero:

<a href="download.php?file=document.pdf" target="_blank">SCARICA IL FILE</a>

 

La classe ForceDownload

Essendo questa un operazione che integro spesso nei miei siti ho creato la classe ForceDownload la quale segue il medesimo approccio ma con la comodità di snellire tutta la procedura.

Ecco di seguito il link per il download della classe.

DOWNLOAD​​

Il suo utilizzo è molto semplice. Il file download.php sarà molto più sinteticamente il seguente:

<?php
require_once('ForceDownload.class.php');
$dir = "download/";  
$file = isset($_GET['file']) ?  $_GET['file']  : ''; 
$download = New ForceDownload($dir, $file);
$download->download() or die ($download->get_error());

 

Come in precedenza basterà un link al file downalod con indicazione nella query string nella variabile get "file" del nome del file.

 

Conclusioni

Le due tecniche sono descritte come alternative ma alle volte l'una è da preferire all'altra. Personalmente preferisco adottare quella con php dato.

 

Se hai avuto problemi nell'implementare tale funzionalità lasciami pure un commento. Se invece ti sono stato di aiuto condividi questo articolo sui social e iscriviti alla mia fan page così da essere aggiornato sui prossimi articoli.

Olimpio Romanella

Sono un appassionato di Web Developing con un particolare debole per php. Mi dedico principalmente dello sviluppo back-end ed in particolare programmazione lato server con php, sviluppo di database relazionali MySql e progettazione di CMS di piccole e medie dimensioni.

Mi avvalgo del framework javascript Jquery, utilizzando molti dei suoi plugin e nei dei miei progetti utilizzo spesso il framework MVC Codeigniter.

10 Commenti presenti

avatar Claudio

Claudio

20 May 2014 ore 17:29

Ciao Olimpio,
sto provando e riprovando lo script per il download di file, ma viene sempre visualizzata la finestra di dialogo.

Ho eseguito l'esempio che ho scaricato dal tuo sito, ma mi chiede sempre se voglio aprirlo oppure salvarlo.
Io vorrei che il download dei file contenuti all'interno della cartella venisse eseguito senza l'apertura della finestra di salvataggio.

avatar Olimpio Romanella

Olimpio Romanella

20 May 2014 ore 16:13

@Claudio: Provare per credere!

avatar Claudio

Claudio

20 May 2014 ore 09:16

Ciao Riccardo,
mi sono casualmente imbattuto nel tuo sito perchè sto effettuando ricerche su come effettuare il download di una cartella, contenente file .csv, dal server a computer locale. L'operazione deve avveniere in maniera del tutto trasparente, cioè senza la visualizzazione della finestra di dialogo.
E' possibile fare ciò?

Grazie

avatar Ricky

Ricky

18 September 2013 ore 19:30

Grazie, dopo tante ore mi hai risolto un problema non da poco

avatar angelo

angelo

05 August 2013 ore 19:21

Ti ho posto male il quesito:
a me serve semplicemente che i file di cui faccio il download ,senza specificare nulla all'interno di download.php. vada automaticamente a finire in una cartella specifica taita00x per l'utente x;tale cartella è gia predefinita all'interno di htdocs; il sito lo chiamo all'interno del download con le istruzioni


$paginapippo="http://www.pippo.it";
echo "<script language=\"JavaScript\">\n";
echo "window.location.href=(\"$paginapippo\");\n";
echo "</script>";
navigo all'interno del sito,

scelgo il file e ne effettuo il download;il download lo implementa il server http://www.pippo.it; adesso il download finisce nella cartella preimpostata del browser per il download, io voglio che rimanga all'interno di una cartella preimpostata sul server taita00x che varia in relazione all'utente x. Grazie in anticipo , saluti, Angelo

avatar angelo

angelo

05 August 2013 ore 19:04

articolo veramente interessante;la classe è eccellente , hai avuto una buona idea;ho necessità di scaricare dei file .zip che prelevo da un sito pippi.com sul mio web server , architettura wamp all'interno di una cartella predefinita che di volta in volta , in relazione all'utente varia;tale cartella è gia precostituita per utente, ad esempio taita000, taita001,taita002...per l'utente 0,1 ,2, ....;se ho ben capito è sufficiente specificare la $dir="C:/.../.../htdocs/taita00x" in relazione all'utente x che si collega , o sbaglio?Ti ringrazio in anticipo per la risposta

avatar oly1982

oly1982

12 April 2013 ore 21:23

@Riccardo: certo che puoi. Devi impostare i corretti heardes per le immagini.

La parte con gli headers dello presente dello script in questo articolo dovrai sostituire con il seguente:
switch( strlower($extension) ) {
case "gif":
$mime_type = "image/gif";
break;
case "png":
$mime_type = "image/png";
break;
case "jpeg":
case "jpg":
$mime_type = "image/jpg";
break;
default:
$mime_type = "";
break;
}

header("Cache-Control: no-cache, must-revalidate");
header('Expires: 0');
header('Content-type: ' . $mime_type);

L'ho scritto alla veloce ti dovrà venir fuori una cosa di questo tipo.

avatar riccardo

riccardo

12 April 2013 ore 12:45

tutto molto chiaro. la mia cartella da proteggere contiene delle immagini. Se io volessi consentire da PHP, oltre al download, la visualizzazione "forzata" delle immagini, è possibile? Sono immagini che è consentito scaricare solo se si è raggiunto un certo limite di crediti, altrimenti no.

avatar oly1982

oly1982

28 January 2012 ore 19:43

Trattandosi di un codice "tradizionale" mi sembra un pò strano.
Mi vengono in mente due cose
1) mancanza del modulo di apache mod_headers.c (molto raro)
2) Conflitti con il rewrite url

avatar Domenico

Domenico

28 January 2012 ore 18:58

Ciao, ho il seguente problema:
ho provato a creare un file .htaccess nella cartella che contiene i miei file destinati al download ed ho scritto al suo interno le direttiva indicata nel tuo articolo ovvero:

<FilesMatch "\.(?i:doc|xls|pdf|mp3|txt)">
ForceType application/octet-stream
Header set Content-Disposition attachment
</FilesMatch>

eppure quando clicco sul link diretto al file, di cui un esempio: <a href='files/nomefile.mp3'>Vai</a>, il risultato è una pagina bianca con Errore del Server! Errore 500.

Premetto che ho un altro .htaccess nella root del mio sito che contiene solo indicazioni mod_rewrite.
Ti ringrazione per l'attenzione se riuscissi a chiarirmi le idee ti sarei davvero suer grato!!! Grazie