Infocurci - programmatore Php Roma
Infocurci - programmatore Php Roma
Questo sito non lascia nessun cookie sul vostro pc, consuma pochissimi kb, non profila nulla e non raccoglie dati personali. Siete i benvenuti.

Php : Come forzare il download di un file

Grazie a poche righe di codice possiamo forzare l'apertura della finestra di download file sui link a risorse multimediali del nostro sito. In questo modo saremo sicuri che l'utente eseguirà il download senza dover necessariamente aprire fastidiosi viewer o player integrati.

Php

Non sempre l'apertura di un file mutlimediale attraverso il metodo predefinito del browser è un comportamento piacevole per l'utente. Spesso infatti l'installazione di player o viewer costringe l'apertura di un file direttamente all'interno del programma usato per la navigazione, causando comportamenti potenzialmente fuorvianti. Si pensi ad esempio ad un utente alle prese con una videolezione di una piattaforma elearning, che viene aperta da un software come windows media player costringendo a lunghi tempi di attesa prima di visualizzare un fotogramma e che non consente ad un allievo inesperto di salvare il video per rivederlo in un secondo tempo.
La finestra di download, per quanto spartana, consente all'utente di scegliere dove salvare il contenuto e di sapere in percentuale a quale punto è arrivato.

Con Php possiamo forzare il download del file con poche righe di codice; possiamo anche scegliere un nome diverso da quello con il quale il documento è salvato sul server.
Ecco una prima funzione, da usare quando il file richiesto risiede sul nostro server:
<?php
    function download_file($file_name_user, $file_name=null, $string_convert=null, $public_dir=null) {
        if (!empty($file_name_user)) {
            if (!empty($file_name)) {        // download a real file
                $file_on_server = $file_name;
                $delete_tmp_file = false;
            }
            elseif (!empty($string_convert) && !empty($public_dir)) {    // download an on-the-fly created file
                if ($public_dir{strlen($public_dir)-1}!='/')    // adds the slash at the end of the path
                    $public_dir .= '/';
               
                // creates an unique name for the temp. file
                $timenow = getdate();
                $filename_rand = 'tmp_'.num2str($timenow["year"], 4).num2str($timenow["mon"], 2).num2str($timenow["mday"], 2).num2str($timenow["hours"], 2).num2str($timenow["minutes"], 2).num2str($timenow["seconds"], 2).num2str(rand(0,100).rand(0,100), 5);
                unset($timenow);
               
                $file_pointer = fopen($public_dir.$filename_rand.'_'.$file_name_user, "w");
                if (fwrite($file_pointer, $string_convert)!=null) {
                    $file_on_server = $public_dir.$filename_rand.'_'.$file_name_user;
                    $delete_tmp_file = true;
                }
                fclose($file_pointer);
                unset($file_pointer);
            }
            else{
                exit;
            }
            if (file_exists($file_on_server) && $fd=fopen($file_on_server, "r")){
                $size = filesize($file_on_server);
               
                header("Pragma: ");
                header("Cache-Control: ");
                header("Content-type: application/force-download");
                header("Content-Disposition: attachment; filename=\"".$file_name_user."\"");
                header("Content-length: ".$size);

                while(!feof($fd)) {
                    $buffer = fread($fd, 2048);
                    print $buffer;
                }
                fclose($fd);
               
                if ($delete_tmp_file) {        // deletes the temp. file from the server
                    if (file_exists($public_dir.$filename_rand.'_'.$file_name_user)) {
                        unlink($public_dir.$filename_rand.'_'.$file_name_user);
                        unset($filename_rand);
                    }
                }
               
                unset($buffer);
                unset($fd);
                unset($size);
                unset($delete_tmp_file);
                unset($file_on_server);
                unset($can_download);
               
                exit;
            }
            else{
                echo "non esiste $file_on_server";
            }
            unset($file_on_server);
        }
        else{
            exit;
        }
    }
?>

La funzione accetta 4 parametri opzionali (il primo è obbligatorio ma può essere passato anche come stringa vuota):

  • $file_name_user è il nome del file da far scaricare all'utente; questa variabile va passata completa del percorso della cartella (a meno che la funzione non venga lanciata dalla stessa posizione in cui è contenuto);
  • $file_name è il nome che vogliamo venga dato al file dalla finestra di download dell'utente; utile nel caso in cui vogliamo far nascondere il vero nome del file;
  • $string_convert  è il codice da inserire nel file, nel caso in cui volessimo crearne uno al volo. Il file viene creato, inviato in output all'utente e quindi eliminato automaticamente. Va da sè che questo parametro ed il primo, $file_name_user, sono alternativi: se è compilato il primo non viene considerato l'altro e viceversa. Se nessuno dei due è compilato, la funzione esce senza ritornare nulla.
  • $public_dir è il nome della cartella, con opportuni permessi di scrittura, in cui viene creato il file "on-the-fly", se il parametro $string_convert è valorizzato. Questa cartella necessita dei giusti permessi di scrittura.

L'aspetto interessante è che questa funzione lavora anche su file protetti da file .htaccess, per cui è una valida soluzione per file da inviare agli utenti soltanto previa autenticazione.

Se invece il file che vogliamo inviare all'utente non risiede sul nostro server, possiamo usare quest'altra funzione, basata sulla libreria CURL:

<?php
    function download($url) {
        set_time_limit(0);
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
        $r = curl_exec($ch);
        curl_close($ch);
        header('Expires: 0'); // no cache
        header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
        header('Last-Modified: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT');
        header('Cache-Control: private', false);
        header('Content-Type: application/force-download');
        header('Content-Disposition: attachment; filename="' . basename($url) . '"');
        header('Content-Transfer-Encoding: binary');
        header('Content-Length: ' . strlen($r)); // provide file size
        header('Connection: close');
        echo $r;
    }
?>

Questa funzione accetta un unico parametro, l'url del file da scaricare. Visto che il server è esterno, non dispone di tutte le opzioni della precedente. Recentemente l'ho utilizzata per un sito in cui il committente aveva la necessità di far scaricare le immagini all'utente, senza passare per il comando "salva immagine con nome" del tasto destro del mouse.