Pobierz wiele plików za pomocą jednej czynności

109

Nie jestem pewien, czy jest to możliwe przy użyciu standardowych technologii internetowych.

Chcę, aby użytkownik mógł pobrać wiele plików za jednym razem. Oznacza to kliknięcie pól wyboru obok plików, a następnie pobranie wszystkich zaznaczonych plików.

Czy to możliwe - jeśli tak, jaką podstawową strategię Pan poleca. Wiem, że mogę użyć technologii Comets do tworzenia zdarzeń po stronie serwera, które wyzwalają HttpResponse, ale mam nadzieję, że istnieje prostszy sposób.

Ankur
źródło

Odpowiedzi:

60

HTTP nie obsługuje jednoczesnego pobierania więcej niż jednego pliku.

Istnieją dwa rozwiązania:

  • Otwórz x liczbę okien, aby zainicjować pobieranie plików (można to zrobić za pomocą JavaScript)
  • preferowane rozwiązanie utwórz skrypt do spakowania plików
Jacob Relkin
źródło
39
Dlaczego plik ZIP jest preferowanym rozwiązaniem? Tworzy dodatkowy krok dla użytkownika (rozpakowywanie).
speedplane
7
Ta strona zawiera javascript, który tworzy plik ZIP. Spójrz na stronę, na której znajduje się świetny przykład. stuk.github.io/jszip
Netsi1964
Trzecim sposobem jest umieszczenie plików w pliku SVG. Jeśli pliki są wyświetlane w przeglądarce, SVG wydaje się najlepszym sposobem.
VectorVortec
4
Sam HTTP obsługuje format wiadomości wieloczęściowych. Ale przeglądarki przenośnie nie analizują odpowiedzi wieloczęściowych po stronie serwera, ale technicznie nie ma w tym nic trudnego.
CMCDragonkai
2
To może być doskonałe rozwiązanie dzięki javascript github.com/sindresorhus/multi-download
juananruiz
84

var links = [
  'https://s3.amazonaws.com/Minecraft.Download/launcher/Minecraft.exe',
  'https://s3.amazonaws.com/Minecraft.Download/launcher/Minecraft.dmg',
  'https://s3.amazonaws.com/Minecraft.Download/launcher/Minecraft.jar'
];

function downloadAll(urls) {
  var link = document.createElement('a');

  link.setAttribute('download', null);
  link.style.display = 'none';

  document.body.appendChild(link);

  for (var i = 0; i < urls.length; i++) {
    link.setAttribute('href', urls[i]);
    link.click();
  }

  document.body.removeChild(link);
}
<button onclick="downloadAll(window.links)">Test me!</button>

Matěj Pokorný
źródło
3
Pracuję z wieloma typami plików, w tym ze zdjęciami, i to działało najlepiej. Jednak link.setAttribute('download', null);zmieniono nazwy wszystkich moich plików na null.
tehlivi
7
Nie działa w IE 11, pobiera tylko .jar (ostatnia pozycja na liście). To było idealne rozwiązanie :(
Immutable Brick
1
@AngeloMoreira Tak, przynajmniej działa w Edge. Jeśli spróbujesz pobierania wielu plików w IE na SM miejscach, na przykład , że tarło wielu okien pop-up, więc myślę, że najlepszym rozwiązaniem dla IE jest nadal z Dmitrijem Nogin powyżej .
Matěj Pokorný
1
@tehlivi - znalazłem to samo. Dodaj link.setAttribute('download',filename)wewnętrzną pętlę. Dzięki temu możesz dowolnie nazywać pliki. Uważam też, że musi to być nazwa pliku bez adresu URL. Skończyło się na wysłaniu dwóch tablic: jednej z pełnym adresem URL, a drugiej z samą nazwą pliku.
PhilMDev
7
Nie działa poprawnie w Chrome v75, Windows 10: Jedyny pobierany plik to Minecraft.jar.
andreivictor
54

Możesz utworzyć tymczasowy zestaw ukrytych ramek iframe, zainicjować pobieranie w nich GET lub POST, poczekać na rozpoczęcie pobierania i usunąć ramki iframe:

<!DOCTYPE HTML>
<html>
<body>
  <button id="download">Download</button> 

  <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
  <script type="text/javascript">

     $('#download').click(function() {
       download('http://nogin.info/cv.doc','http://nogin.info/cv.doc');
     });

     var download = function() {
       for(var i=0; i<arguments.length; i++) {
         var iframe = $('<iframe style="visibility: collapse;"></iframe>');
         $('body').append(iframe);
         var content = iframe[0].contentDocument;
         var form = '<form action="' + arguments[i] + '" method="GET"></form>';
         content.write(form);
         $('form', content).submit();
         setTimeout((function(iframe) {
           return function() { 
             iframe.remove(); 
           }
         })(iframe), 2000);
       }
     }      

  </script>
</body>
</html>

Lub bez jQuery:

 function download(...urls) {
    urls.forEach(url => {
      let iframe = document.createElement('iframe');
      iframe.style.visibility = 'collapse';
      document.body.append(iframe);

      iframe.contentDocument.write(
        `<form action="${url.replace(/\"/g, '"')}" method="GET"></form>`
      );
      iframe.contentDocument.forms[0].submit();

      setTimeout(() => iframe.remove(), 2000);
    });
  }
Dmitry Nogin
źródło
niesamowite, ale z pewnych powodów pliki nie są pobierane. Wydaje mi się, że powodem jest to, że strona ładuje się ponownie po wykonaniu skryptu, wydaje się, że przyczyną nie jest pobieranie plików. Masz jakąś wskazówkę, co robię źle?
Chirag Mehta
Mam wiele problemów z tym rozwiązaniem. W IE, ponieważ moje okno nadrzędne zmieniło document.domain, odmowa dostępu. Jest wiele postów o tym, jak to naprawić, ale wszystkie wydają się zepsute. W przeglądarce Chrome użytkownik otrzymuje komunikat ostrzegawczy informujący witrynę o próbie pobrania wielu plików (ale przynajmniej działa). W przeglądarce Firefox pojawia się inne okno pobierania, ale po kliknięciu przycisku Zapisz nie pojawia się okno dialogowe zapisywania pliku ...
Melanie
U mnie to nie zadziałało, ponieważ okno dialogowe pliku „blokuje” inne okna dialogowe zapisu. To, co zrobiłem, było trochę hackerskie - akcja mousemove rejestruje się dopiero po zniknięciu okna dialogowego pliku, więc użyłem tego - ale nie jest to testowane. Dodam to jako kolejną odpowiedź.
Karel Bílek
2
Czy to działa w IE10? Otrzymuję: Obiekt nie obsługuje właściwości lub metody „zapisu”
Hoppe
dlaczego zwrócona funkcja (zamknięcie?) na setTimeout()?
robisrob
34

To rozwiązanie działa w różnych przeglądarkach i nie powoduje ostrzeżeń. Zamiast tworzyć plik iframe, tutaj tworzymy łącze do każdego pliku. Zapobiega to wyświetlaniu się komunikatów ostrzegawczych.

Do obsługi części zapętlonej używamy setTimeout, co jest niezbędne, aby działała w IE.

/**
 * Download a list of files.
 * @author speedplane
 */
function download_files(files) {
  function download_next(i) {
    if (i >= files.length) {
      return;
    }
    var a = document.createElement('a');
    a.href = files[i].download;
    a.target = '_parent';
    // Use a.download if available, it prevents plugins from opening.
    if ('download' in a) {
      a.download = files[i].filename;
    }
    // Add a to the doc for click to work.
    (document.body || document.documentElement).appendChild(a);
    if (a.click) {
      a.click(); // The click method is supported by most browsers.
    } else {
      $(a).click(); // Backup using jquery
    }
    // Delete the temporary link.
    a.parentNode.removeChild(a);
    // Download the next file with a small timeout. The timeout is necessary
    // for IE, which will otherwise only download the first file.
    setTimeout(function() {
      download_next(i + 1);
    }, 500);
  }
  // Initiate the first download.
  download_next(0);
}
<script>
  // Here's a live example that downloads three test text files:
  function do_dl() {
    download_files([
      { download: "http://www.nt.az/reg.txt", filename: "regs.txt" },
      { download: "https://www.w3.org/TR/PNG/iso_8859-1.txt", filename: "standards.txt" },
      { download: "http://qiime.org/_static/Examples/File_Formats/Example_Mapping_File.txt", filename: "example.txt" },
    ]);
  };
</script>
<button onclick="do_dl();">Test downloading 3 text files.</button>

speedplane
źródło
To jest jedyny tutaj, który działał dla mnie, ponieważ muszę obsługiwać IE. Dziękuję Ci.
Øystein Amundsen
1
Ta odpowiedź jest złota. Tylko taki, który działa we wszystkich przeglądarkach bez komunikatu ostrzegawczego. Specjalnie IE. Genialne rzeczy
Mukul Goel
Nie działa w systemie Chrome OSX, prosi mnie o zezwolenie na wielokrotne pobieranie, ale nawet jeśli to zrobię, pobierany jest tylko pierwszy plik i usłyszałem ilość „sygnału dźwiękowego” odpowiadającą liczbie plików do pobrania
Allan Raquin
2
Przycisk nic nie robi Google Chrome Version 76.0.3809.100 (Official Build) (64-bit).
1934286
1
Przycisk nie działa w przypadku przepełnienia stosu Uruchom fragment kodu. Browser Crome @speedplane
mb
5

Najłatwiejszym sposobem byłoby udostępnienie wielu plików spakowanych w plik ZIP.

Przypuszczam, że możesz zainicjować pobieranie wielu plików za pomocą wielu ramek iframe lub wyskakujących okienek, ale z punktu widzenia użyteczności plik ZIP jest jeszcze lepszy. Kto chce klikać dziesięć okien dialogowych „Zapisz jako”, które otworzy przeglądarka?

Thilo
źródło
3
Zdaję sobie sprawę, że odpowiedź pochodzi z 2010 roku, ale wielu użytkowników korzysta obecnie ze smartfonów, z których niektórzy nie mogą domyślnie otwierać zamków (znajomy mówi mi, że jego Samsung S4 Active nie może otwierać zamków).
Hydraxan14
4

Zgadzam się, że plik zip jest lepszym rozwiązaniem ... Ale jeśli musisz przesłać wiele plików, oto rozwiązanie, które wymyśliłem. Działa w IE 9 i nowszych (być może też niższych wersjach - nie testowałem), Firefox, Safari i Chrome. Chrome wyświetli komunikat do użytkownika, aby uzyskać zgodę na pobranie wielu plików przy pierwszym użyciu witryny.

function deleteIframe (iframe) {
    iframe.remove(); 
}
function createIFrame (fileURL) {
    var iframe = $('<iframe style="display:none"></iframe>');
    iframe[0].src= fileURL;
    $('body').append(iframe);
    timeout(deleteIframe, 60000, iframe);             
 }
 // This function allows to pass parameters to the function in a timeout that are 
 // frozen and that works in IE9
 function timeout(func, time) {
      var args = [];
      if (arguments.length >2) {
           args = Array.prototype.slice.call(arguments, 2);
      }
      return setTimeout(function(){ return func.apply(null, args); }, time);
 }
 // IE will process only the first one if we put no delay
 var wait = (isIE ? 1000 : 0);
 for (var i = 0; i < files.length; i++) {  
      timeout(createIFrame, wait*i, files[i]);
 }

Jedynym efektem ubocznym tej techniki jest to, że użytkownik zobaczy opóźnienie między przesłaniem a wyświetleniem okna dialogowego pobierania. Aby zminimalizować ten efekt, sugeruję użycie techniki opisanej tutaj i na to pytanie Wykryj, kiedy przeglądarka odbiera pobieranie pliku, które polega na ustawieniu pliku cookie z Twoim plikiem, aby wiedzieć, że rozpoczął się pobieranie. Będziesz musiał sprawdzić ten plik cookie po stronie klienta i wysłać go po stronie serwera. Nie zapomnij ustawić właściwej ścieżki do pliku cookie, w przeciwnym razie możesz go nie widzieć. Będziesz także musiał dostosować rozwiązanie do pobierania wielu plików.

Melanie
źródło
4

Odpowiedzi w wersji jQuery elementu iframe:

function download(files) {
    $.each(files, function(key, value) {
        $('<iframe></iframe>')
            .hide()
            .attr('src', value)
            .appendTo($('body'))
            .load(function() {
                var that = this;
                setTimeout(function() {
                    $(that).remove();
                }, 100);
            });
    });
}
Yirmiyahu Fischer
źródło
Każdy szuka tablicy. To zadziała: download(['http://nogin.info/cv.doc','http://nogin.info/cv.doc']);nie działa to jednak w przypadku pobierania plików graficznych.
tehlivi
3

Rozwiązanie kątowe:

HTML

    <!doctype html>
    <html ng-app='app'>
        <head>
            <title>
            </title>
            <link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
            <link rel="stylesheet" href="style.css">
        </head>
        <body ng-cloack>        
            <div class="container" ng-controller='FirstCtrl'>           
              <table class="table table-bordered table-downloads">
                <thead>
                  <tr>
                    <th>Select</th>
                    <th>File name</th>
                    <th>Downloads</th>
                  </tr>
                </thead>
                <tbody>
                  <tr ng-repeat = 'tableData in tableDatas'>
                    <td>
                        <div class="checkbox">
                          <input type="checkbox" name="{{tableData.name}}" id="{{tableData.name}}" value="{{tableData.name}}" ng-model= 'tableData.checked' ng-change="selected()">
                        </div>
                    </td>
                    <td>{{tableData.fileName}}</td>
                    <td>
                        <a target="_self" id="download-{{tableData.name}}" ng-href="{{tableData.filePath}}" class="btn btn-success pull-right downloadable" download>download</a>
                    </td>
                  </tr>              
                </tbody>
              </table>
                <a class="btn btn-success pull-right" ng-click='downloadAll()'>download selected</a>

                <p>{{selectedone}}</p>
            </div>
            <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
            <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
            <script src="script.js"></script>
        </body>
    </html>

app.js

var app = angular.module('app', []);            
app.controller('FirstCtrl', ['$scope','$http', '$filter', function($scope, $http, $filter){

$scope.tableDatas = [
    {name: 'value1', fileName:'file1', filePath: 'data/file1.txt', selected: true},
    {name: 'value2', fileName:'file2', filePath: 'data/file2.txt', selected: true},
    {name: 'value3', fileName:'file3', filePath: 'data/file3.txt', selected: false},
    {name: 'value4', fileName:'file4', filePath: 'data/file4.txt', selected: true},
    {name: 'value5', fileName:'file5', filePath: 'data/file5.txt', selected: true},
    {name: 'value6', fileName:'file6', filePath: 'data/file6.txt', selected: false},
  ];  
$scope.application = [];   

$scope.selected = function() {
    $scope.application = $filter('filter')($scope.tableDatas, {
      checked: true
    });
}

$scope.downloadAll = function(){
    $scope.selectedone = [];     
    angular.forEach($scope.application,function(val){
       $scope.selectedone.push(val.name);
       $scope.id = val.name;        
       angular.element('#'+val.name).closest('tr').find('.downloadable')[0].click();
    });
}         


}]);

działający przykład: https://plnkr.co/edit/XynXRS7c742JPfCA3IpE?p=preview

suresh
źródło
1

Aby poprawić odpowiedź @Dmitry Nogin: to zadziałało w moim przypadku.

Jednak nie jest to testowane, ponieważ nie jestem pewien, jak działa okno dialogowe plików w różnych kombinacjach systemu operacyjnego / przeglądarki. (Stąd wiki społeczności.)

<script>
$('#download').click(function () {
    download(['http://www.arcelormittal.com/ostrava/doc/cv.doc', 
              'http://www.arcelormittal.com/ostrava/doc/cv.doc']);
});

var download = function (ar) {
    var prevfun=function(){};
    ar.forEach(function(address) {  
        var pp=prevfun;
        var fun=function() {
                var iframe = $('<iframe style="visibility: collapse;"></iframe>');
                $('body').append(iframe);
                var content = iframe[0].contentDocument;
                var form = '<form action="' + address + '" method="POST"></form>';
                content.write(form);
                $(form).submit();
                setTimeout(function() {    
                    $(document).one('mousemove', function() { //<--slightly hacky!
                        iframe.remove();
                        pp();
                    });
                },2000);
        }
        prevfun=fun; 
      });
      prevfun();   
}
</script>
Karel Bílek
źródło
1

Działa to we wszystkich przeglądarkach (IE11, Firefox, Edge, Chrome i Chrome Mobile) Moje dokumenty są w wielu wybranych elementach. Wygląda na to, że przeglądarki mają problemy, gdy próbujesz zrobić to zbyt szybko ... Więc użyłem limitu czasu.

//user clicks a download button to download all selected documents
$('#downloadDocumentsButton').click(function () {
    var interval = 1000;
    //select elements have class name of "document"
    $('.document').each(function (index, element) {
        var doc = $(element).val();
        if (doc) {
            setTimeout(function () {
                window.location = doc;
            }, interval * (index + 1));
        }
    });
});

To rozwiązanie wykorzystujące obietnice:

 function downloadDocs(docs) {
        docs[0].then(function (result) {
            if (result.web) {
                window.open(result.doc);
            }
            else {
                window.location = result.doc;
            }
            if (docs.length > 1) {
                setTimeout(function () { return downloadDocs(docs.slice(1)); }, 2000);
            }
        });
    }

 $('#downloadDocumentsButton').click(function () {
        var files = [];
        $('.document').each(function (index, element) {
            var doc = $(element).val();
            var ext = doc.split('.')[doc.split('.').length - 1];

            if (doc && $.inArray(ext, docTypes) > -1) {
                files.unshift(Promise.resolve({ doc: doc, web: false }));
            }
            else if (doc && ($.inArray(ext, webTypes) > -1 || ext.includes('?'))) {
                files.push(Promise.resolve({ doc: doc, web: true }));
            }
        });

        downloadDocs(files);
    });
Zach Painter
źródło
1

Zdecydowanie najłatwiejsze rozwiązanie (przynajmniej w systemie ubuntu / linux):

  • utwórz plik tekstowy z adresami URL plików do pobrania (np. plik.txt)
  • umieść plik „file.txt” w katalogu, do którego chcesz pobrać pliki
  • otwórz terminal w katalogu pobierania z poprzedniego lin
  • pobierz pliki za pomocą polecenia „wget -i plik.txt”

Działa jak marzenie.

Martijn
źródło
Nie rozumiem, dlaczego jest to odrzucane. To działa doskonale, dziękuję bardzo.
Martin Fürholz
1

Aby rozwiązać ten problem, stworzyłem bibliotekę JS do przesyłania strumieniowego wielu plików bezpośrednio do zip po stronie klienta. Główną unikalną cechą jest to, że nie ma ograniczeń rozmiaru z pamięci (wszystko jest przesyłane strumieniowo) ani formatu zip (używa zip64, jeśli zawartość jest większa niż 4 GB).

Ponieważ nie wykonuje kompresji, jest również bardzo wydajny.

Znajdź plik „downzip” na npm lub github !

DebboR
źródło
1

Poniższy skrypt wykonał tę pracę z wdziękiem.

var urls = [
'https://images.pexels.com/photos/432360/pexels-photo-432360.jpeg',
'https://images.pexels.com/photos/39899/rose-red-tea-rose-regatta-39899.jpeg'
];

function downloadAll(urls) {


  for (var i = 0; i < urls.length; i++) {
    forceDownload(urls[i], urls[i].substring(urls[i].lastIndexOf('/')+1,urls[i].length))
  }
}
function forceDownload(url, fileName){
    var xhr = new XMLHttpRequest();
    xhr.open("GET", url, true);
    xhr.responseType = "blob";
    xhr.onload = function(){
        var urlCreator = window.URL || window.webkitURL;
        var imageUrl = urlCreator.createObjectURL(this.response);
        var tag = document.createElement('a');
        tag.href = imageUrl;
        tag.download = fileName;
        document.body.appendChild(tag);
        tag.click();
        document.body.removeChild(tag);
    }
    xhr.send();
}
Shyam Narayan
źródło
0

Szukam rozwiązania, aby to zrobić, ale rozpakowanie plików w javascript nie było tak czyste, jak mi się podobało. Zdecydowałem się zamknąć pliki w jednym pliku SVG.

Jeśli masz pliki zapisane na serwerze (ja nie mam), możesz po prostu ustawić href w SVG.

W moim przypadku przekonwertuję pliki do base64 i osadzę je w SVG.

Edycja: SVG działał bardzo dobrze. Jeśli masz zamiar tylko pobrać pliki, ZIP może być lepszy. Jeśli masz zamiar wyświetlić pliki, SVG wydaje się lepszy.

VectorVortec
źródło
0

Korzystając z komponentów Ajax, można rozpocząć pobieranie wielu plików. Dlatego musisz użyć https://cwiki.apache.org/confluence/display/WICKET/AJAX+update+and+file+download+in+one+blow

Dodaj wystąpienie AJAXDownload do swojej strony lub cokolwiek innego. Utwórz AjaxButton i zastąp onSubmit. Utwórz zachowanie AbstractAjaxTimerBehavior i rozpocznij pobieranie.

        button = new AjaxButton("button2") {

        private static final long serialVersionUID = 1L;

        @Override
        protected void onSubmit(AjaxRequestTarget target, Form<?> form)
        {
            MultiSitePage.this.info(this);
            target.add(form);

            form.add(new AbstractAjaxTimerBehavior(Duration.milliseconds(1)) {

                @Override
                protected void onTimer(AjaxRequestTarget target) {
                    download.initiate(target);
                }

            });     
        }

Miłego pobierania!

kleenxcoder
źródło
javascrpt?!?!?!?!?!
bluejayke
0

Poniżej kod w 100% działający.

Krok 1 : Wklej poniższy kod w pliku index.html

<!DOCTYPE html>
<html ng-app="ang">

<head>
    <title>Angular Test</title>
    <meta charset="utf-8" />
</head>

<body>
    <div ng-controller="myController">
        <button ng-click="files()">Download All</button>
    </div>

    <script src="angular.min.js"></script>
    <script src="index.js"></script>
</body>

</html>

Krok 2 : Wklej poniżej kodu w index.js pliku

"use strict";

var x = angular.module('ang', []);

    x.controller('myController', function ($scope, $http) {
        var arr = [
            {file:"http://localhost/angularProject/w3logo.jpg", fileName: "imageone"},
            {file:"http://localhost/angularProject/cv.doc", fileName: "imagetwo"},
            {file:"http://localhost/angularProject/91.png", fileName: "imagethree"}
        ];

        $scope.files = function() {
            angular.forEach(arr, function(val, key) {
                $http.get(val.file)
                .then(function onSuccess(response) {
                    console.log('res', response);
                    var link = document.createElement('a');
                    link.setAttribute('download', val.fileName);
                    link.setAttribute('href', val.file);
                    link.style.display = 'none';
                    document.body.appendChild(link);
                    link.click(); 
                    document.body.removeChild(link);
                })
                .catch(function onError(error) {
                    console.log('error', error);
                })
            })
        };
    });

UWAGA : Upewnij się, że wszystkie trzy pliki, które mają zostać pobrane, zostaną umieszczone w tym samym folderze wraz z plikami angularProject / index.html lub angularProject / index.js .

solanki ...
źródło
Czy u rilly ugniatasz ayng [ostatni władca powietrza] ular dla thuis / ???
bluejayke
0

Pobieranie listy adresów URL z wywołaniem ajax, a następnie użycie wtyczki jquery do równoległego pobierania wielu plików.

  $.ajax({
        type: "POST",
        url: URL,
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        data: data,
        async: true,
        cache: false,
        beforeSend: function () {
            blockUI("body");
        },
        complete: function () { unblockUI("body"); },
        success: function (data) {
           //here data --> contains list of urls with comma seperated
            var listUrls= data.DownloadFilePaths.split(',');
            listUrls.forEach(function (url) {
                $.fileDownload(url);
            });
            return false; 
        },
        error: function (result) {
            $('#mdlNoDataExist').modal('show');
        }

    });
Ali
źródło
0

Oto sposób, w jaki to robię. Otwieram wiele plików ZIP, ale także innego rodzaju dane (eksportuję projekt w formacie PDF i jednocześnie wiele plików ZIP z dokumentem).

Po prostu skopiowałem część mojego kodu. Połączenie z przycisku na liście:

$url_pdf = "pdf.php?id=7";
$url_zip1 = "zip.php?id=8";
$url_zip2 = "zip.php?id=9";
$btn_pdf = "<a href=\"javascript:;\" onClick=\"return open_multiple('','".$url_pdf.",".$url_zip1.",".$url_zip2."');\">\n";
$btn_pdf .= "<img src=\"../../../images/icones/pdf.png\" alt=\"Ver\">\n";
$btn_pdf .= "</a>\n"

Czyli podstawowe wywołanie procedury JS (podstawowe zasady!). oto procedura JS:

 function open_multiple(base,url_publication)
 {
     // URL of pages to open are coma separated
     tab_url = url_publication.split(",");
     var nb = tab_url.length;
     // Loop against URL    
     for (var x = 0; x < nb; x++)
     {
        window.open(tab_url[x]);
      }

     // Base is the dest of the caller page as
     // sometimes I need it to refresh
     if (base != "")
      {
        window.location.href  = base;
      }
   }

Sztuczka polega na tym, aby NIE podawać bezpośredniego linku do pliku ZIP, ale wysłać go do przeglądarki. Lubię to:

  $type_mime = "application/zip, application/x-compressed-zip";
 $the_mime = "Content-type: ".$type_mime;
 $tdoc_size = filesize ($the_zip_path);
 $the_length = "Content-Length: " . $tdoc_size;
 $tdoc_nom = "Pesquisa.zip";
 $the_content_disposition = "Content-Disposition: attachment; filename=\"".$tdoc_nom."\"";

  header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
  header("Expires: Sat, 26 Jul 1997 05:00:00 GMT");   // Date in the past
  header($the_mime);
  header($the_length);
  header($the_content_disposition);

  // Clear the cache or some "sh..." will be added
  ob_clean();
  flush();
  readfile($the_zip_path);
  exit();
Piotr
źródło
-1
           <p class="style1">



<a onclick="downloadAll(window.links)">Balance Sheet Year 2014-2015</a>

</p>

<script>
 var links = [
  'pdfs/IMG.pdf',
  'pdfs/IMG_0001.pdf',
 'pdfs/IMG_0002.pdf',
 'pdfs/IMG_0003.pdf',
'pdfs/IMG_0004.pdf',
'pdfs/IMG_0005.pdf',
 'pdfs/IMG_0006.pdf'

];

function downloadAll(urls) {
  var link = document.createElement('a');

  link.setAttribute('download','Balance Sheet Year 2014-2015');
  link.style.display = 'none';

  document.body.appendChild(link);

  for (var i = 0; i < urls.length; i++) {
    link.setAttribute('href', urls[i]);
    link.click();
  }

  document.body.removeChild(link);
}
</script>

źródło