hoe kan ik een .zip bestand downloaden via ajax request
Via een anker roep ik de jquery ajax aan die vervolgesn het php script aanroept.
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<a href="#download" class="cb_down" title="Download">Download</a>
// AJAX for Checkbox download
$(document).on('click' , '.cb_down' , function() {
var checkboxes_down = [];
$('.rafcheckbox').each(function() {
if(this.checked) {
checkboxes_down.push($(this).val());
}
});
checkboxes_down = checkboxes_down.toString();
$.ajax({
url:"",
method:"POST",
data:{ checkboxes_down:checkboxes_down },
success:function(response){
// geen response nodig
}
});
});
// AJAX for Checkbox download
$(document).on('click' , '.cb_down' , function() {
var checkboxes_down = [];
$('.rafcheckbox').each(function() {
if(this.checked) {
checkboxes_down.push($(this).val());
}
});
checkboxes_down = checkboxes_down.toString();
$.ajax({
url:"",
method:"POST",
data:{ checkboxes_down:checkboxes_down },
success:function(response){
// geen response nodig
}
});
});
De php:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// Multiple download (checkboxes)
if(isset($_POST["checkboxes_down"])) {
// create a tmp folder for the zip file
$tmpfolder = $MainFolderName.'/tmp';
if (!is_dir($tmpfolder)) {
mkdir($tmpfolder, 0755, true);
}
$checkboxfiles = explode("," , $_POST["checkboxes_down"]);
$filename = "archive.zip";
$filepath = $tmpfolder."/";
foreach($checkboxfiles as $checkboxfile) {
Zip($checkboxfile, $tmpfolder."/archive.zip"); // "Zip" is functie die archive.zip file maakt
}
if(file_exists($tmpfolder.'/archive.zip')){
// http headers for zip downloads
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/octet-stream");
header("Content-Disposition: attachment; filename=\"".$filename."\"");
header("Content-Transfer-Encoding: binary");
header("Content-Length: ". filesize($filepath.$filename));
while (ob_get_level()) {
ob_end_clean();
}
readfile($filepath.$filename);
unlink($tmpfolder.'/archive.zip'); // unlink archive.zip
rmdir($tmpfolder); // remove tmpdir
exit;
}
}
if(isset($_POST["checkboxes_down"])) {
// create a tmp folder for the zip file
$tmpfolder = $MainFolderName.'/tmp';
if (!is_dir($tmpfolder)) {
mkdir($tmpfolder, 0755, true);
}
$checkboxfiles = explode("," , $_POST["checkboxes_down"]);
$filename = "archive.zip";
$filepath = $tmpfolder."/";
foreach($checkboxfiles as $checkboxfile) {
Zip($checkboxfile, $tmpfolder."/archive.zip"); // "Zip" is functie die archive.zip file maakt
}
if(file_exists($tmpfolder.'/archive.zip')){
// http headers for zip downloads
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/octet-stream");
header("Content-Disposition: attachment; filename=\"".$filename."\"");
header("Content-Transfer-Encoding: binary");
header("Content-Length: ". filesize($filepath.$filename));
while (ob_get_level()) {
ob_end_clean();
}
readfile($filepath.$filename);
unlink($tmpfolder.'/archive.zip'); // unlink archive.zip
rmdir($tmpfolder); // remove tmpdir
exit;
}
}
Als ik een aantal checkboxen aanvink en op Download klik, wordt de archive.zip gemaakt met alle bestanden erin. Ik heb dit gechecked en dit werkt goed!
Alleen: readfile($filepath.$filename); werkt niet.
Ik heb geen idee waarom ik de .zip niet als download gepresenteerd krijg...
Gewijzigd op 27/02/2019 14:47:30 door Jack Maessen
ik ga hier eens naar kijken. Dankjewel voor reactie
$filepath
'archive.zip'
$tmpfolder
Doen allemaal ongeveer hetzelfde wat het sowieso allemaal vreselijk verwarrend maakt.
Vooral dit:
readfile($filepath.$filename);
unlink($tmpfolder.'/archive.zip');
Terwijl het daar over precies hetzelfde pad+bestand gaat?
Je kunt de PHP los van het formulier/AJAX testen. Doe dit dan ook. Zorg dat dat werkt, en ga dan pas via AJAX testen.
Je zegt "readfile() werkt niet". Wat gebeurt er, en hoe wijkt dit af van het verwachte resultaat?
Enne, wellicht wil je $checkboxfiles onderwerpen aan een controle aan de hand van een whitelist, anders is het misschien mogelijk om arbitraire (en gevoelige) bestanden te downloaden zoals configuratiebestanden en dergelijke...
@Thomas: maar blijkbaar wist jij dat ook niet anders had je me dat direct kunnen zeggen dat dat the main issue was
Gewijzigd op 27/02/2019 18:45:00 door Jack Maessen
Heb je al gekeken in je browser naar de inhoud van je AJAX-request?
Los daarvan, uiteindelijk is het mijn doel om het probleemoplossend vermogen van de vragensteller te vergroten, en niet om enkel ad hoc antwoorden te geven op ad hoc vragen.
@Adoptive: over dat voorbeeld, hoe resulteert het echo'en van een pad+bestandsnaam in een downloadprompt? :/
EDIT: oh, window.location = response; lol, weet niet of ik dat zo zou programmeren.
Gewijzigd op 27/02/2019 21:39:01 door Thomas van den Heuvel
Je moet dit ook niet via AJAX doen, maar gewoon een window.open() (waarbij je dus geen POST kunt doen, maar via de GET moet werken). Door de Content-Disposition: attachment header zal de browser snappen dat ie hiervoor geen nieuwe tab hoeft te openen (dat doet ie wel heel kort, maar die sluit ie meteen weer), maar een download dialoog aan moet bieden.
Op iPad komt onderaan het venster een mini dialoog om zip te downloaden en te openen in een app naar keuze.
Zou het niet logischer zijn dat je naar een download-actie wordt gestuurd via een script, in plaats van een rechtstreekse verwijzing naar een bestand (wat beschikbaar is in de publieke webdirectory)? Dan zou je een constructie als die van @Jack kunnen gebruiken.
Ik gebruik dat om afgeschermde plaatjes op te halen.
Nu moet ik zeggen dat ik dat heb toegepast met plaatjes.
Voor pdf's verwijs ik door naar een nieuwe tab met een url, waarbij niet rechtstreeks de pdf wordt opgehaald, maar eerst PHP controleert of je bent ingelogd en dan wordt readfile() uitgevoerd.
Maar in principe is het mogelijk om de data met base64 over te sturen. En het is vast ook wel mogelijk om met javascript de output door te sturen. Maar ik had toen geen tijd om daar dieper in te duiken.
Ik zou niet met base64 gaan lopen klooien (alleen maar overhead). Gewoon een RewriteRule die /prive/plaatjes/whatever.jpg omschrijft naar prive-plaatje.php?id=whatever. Dan kun je inderdaad gewoon rechten controleren, enz. Via een header() geef je dan de juiste Content-Type mee.
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php // Multiple download (checkboxes)
if(isset($_POST["checkboxes_down"])) {
// create a tmp folder for the zip file
$tmpfolder = $MainFolderName.'/tmp';
if (!is_dir($tmpfolder)) {
mkdir($tmpfolder, 0755, true);
}
$checkboxfiles = explode("," , $_POST["checkboxes_down"]);
$filename = "archive.zip";
$filepath = $tmpfolder."/";
foreach($checkboxfiles as $checkboxfile) {
if( !is_dir($checkboxfile) && count($checkboxfiles) < 2 ) { // if selected only 1 checkbox and is not folder
include('alerts/downloadsingle.php');
exit;
}
else {
Zip($checkboxfile, $tmpfolder."/archive.zip");
}
}
include('alerts/downloadmultiple.php');
exit;
}?>
if(isset($_POST["checkboxes_down"])) {
// create a tmp folder for the zip file
$tmpfolder = $MainFolderName.'/tmp';
if (!is_dir($tmpfolder)) {
mkdir($tmpfolder, 0755, true);
}
$checkboxfiles = explode("," , $_POST["checkboxes_down"]);
$filename = "archive.zip";
$filepath = $tmpfolder."/";
foreach($checkboxfiles as $checkboxfile) {
if( !is_dir($checkboxfile) && count($checkboxfiles) < 2 ) { // if selected only 1 checkbox and is not folder
include('alerts/downloadsingle.php');
exit;
}
else {
Zip($checkboxfile, $tmpfolder."/archive.zip");
}
}
include('alerts/downloadmultiple.php');
exit;
}?>
Als 1 checkbox is aangevinkt:(alerts/downloadsingle.php)
Code (php)
1
2
3
4
5
6
2
3
4
5
6
<div class="alert alert-success echomessage download" role="alert">
<span class="closebtn"><i class="fas fa-times echoclose"></i></span>
<?php echo '<b>' . basename($checkboxfile) . ' </b>ready for download!'; ?>
<br />
<a href="<?php echo $checkboxfile; ?>" class="closebtn downloadsingle btn btn-download" title="Download" download>Download</a>
</div>
<span class="closebtn"><i class="fas fa-times echoclose"></i></span>
<?php echo '<b>' . basename($checkboxfile) . ' </b>ready for download!'; ?>
<br />
<a href="<?php echo $checkboxfile; ?>" class="closebtn downloadsingle btn btn-download" title="Download" download>Download</a>
</div>
Als meerder zijn aangevinkt:(alerts/downloadmultiple.php)
Code (php)
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
<div class="alert alert-success echomessage download" role="alert">
<span class="closebtn"><i class="fas fa-times echoclose"></i></span>
Multiple files ready for download!
<form method="post" action="">
<input type="hidden" name="downloadzip" value="true" />
<button type="submit" class="closebtn downloadzip btn btn-download" name="submit_downloadzip">Download</button>
</form>
</div>
<span class="closebtn"><i class="fas fa-times echoclose"></i></span>
Multiple files ready for download!
<form method="post" action="">
<input type="hidden" name="downloadzip" value="true" />
<button type="submit" class="closebtn downloadzip btn btn-download" name="submit_downloadzip">Download</button>
</form>
</div>
Bij submit multiple gaat ie deze loop in en dan werkt de readfile() wel:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php if($_POST['downloadzip']) {
if(file_exists($MainFolderName . '/tmp/archive.zip')){
$filename = "archive.zip";
// http headers for zip downloads
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/octet-stream");
header("Content-Disposition: attachment; filename=\"".$filename."\"");
header("Content-Transfer-Encoding: binary");
header("Content-Length: ". filesize($MainFolderName . '/tmp/archive.zip'));
while (ob_get_level()) {
ob_end_clean();
}
@readfile($MainFolderName . '/tmp/archive.zip');
unlink($MainFolderName . '/tmp/archive.zip'); // unlink archive.zip
rmdir($MainFolderName . '/tmp'); // remove tmpdir
exit;
}
}?>
if(file_exists($MainFolderName . '/tmp/archive.zip')){
$filename = "archive.zip";
// http headers for zip downloads
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/octet-stream");
header("Content-Disposition: attachment; filename=\"".$filename."\"");
header("Content-Transfer-Encoding: binary");
header("Content-Length: ". filesize($MainFolderName . '/tmp/archive.zip'));
while (ob_get_level()) {
ob_end_clean();
}
@readfile($MainFolderName . '/tmp/archive.zip');
unlink($MainFolderName . '/tmp/archive.zip'); // unlink archive.zip
rmdir($MainFolderName . '/tmp'); // remove tmpdir
exit;
}
}?>
Voordeel vind ik van deze wijze: een single download geeft een anker met download, zodat ie ook aangeboden wordt als download.
Bij multiple: ik kan direct na de readfile() de tmp folder leegmaken
Gewijzigd op 28/02/2019 01:36:17 door Jack Maessen