5

I am creating pdf files on the fly and I want to download multiple files using php. Can I write header like this

<?php
header('Content-type: application/pdf');
header('Content-Disposition: attachment; filename="downloaded.pdf"');
readfile('original.pdf');
?>

in while loop?

Novice
  • 981
  • 6
  • 12
  • 25
  • just in case someone is still looking out for solution to this..i found out it here..blog.drinkncode.com/download-multiple-files-through-loop-in-php – Coder anonymous Feb 11 '16 at 19:49

5 Answers5

6

Short answer is no, you need something to tell the client where the content ends and a new header begins. You can either use the zip utility and package them up for download, or you could look in to maybe a mime email format (which uses dividers throughout the document) but I'm not sure that would work over the HTTP protocol without explicitly calling it an "email" package.

I would just recommend using the zip utility. Generate the PDFs you need to, then package them up and send them off.

Brad Christie
  • 100,477
  • 16
  • 156
  • 200
5

No. HTTP doesn't support multiple files in a single download. There was some talk about adding MIME-style semantics to HTTP messages way back when, so you could embed multiple responses in a single transfer, but that didn't go anywhere.

Unless you do something like zipping the multiple files on the server and transfer that zip, there's no way to download more than one file per request.

Marc B
  • 356,200
  • 43
  • 426
  • 500
3

Step1: Create one index.php file and add following code.

<?php
$path = $_SERVER['DOCUMENT_ROOT']."/your_folder/"; 

$files = scandir($path);
$count=1;
foreach ($files as $filename)
{
    if($filename=="." || $filename==".." || $filename=="download.php" || $filename=="index.php")
    {
        //this will not display specified files
    }
    else
    {
        echo "<label >".$count.".&nbsp;</label>";
        echo "<a href="download.php/?filename=".$filename."">".$filename."</a>
";
        $count++;
    }
}
?>

Step2: Create one download.php file and add following code.

<?php
function output_file($file, $name, $mime_type='')
{
 /*
 This function takes a path to a file to output ($file),  the filename that the browser will see ($name) and  the MIME type of the file ($mime_type, optional).
 */

 //Check the file premission
 if(!is_readable($file)) die('File not found or inaccessible!');

 $size = filesize($file);
 $name = rawurldecode($name);

 /* Figure out the MIME type | Check in array */
 $known_mime_types=array(
  "pdf" => "application/pdf",
  "txt" => "text/plain",
  "html" => "text/html",
  "htm" => "text/html",
 "exe" => "application/octet-stream",
 "zip" => "application/zip",
 "doc" => "application/msword",
 "xls" => "application/vnd.ms-excel",
 "ppt" => "application/vnd.ms-powerpoint",
 "gif" => "image/gif",
 "png" => "image/png",
 "jpeg"=> "image/jpg",
 "jpg" =>  "image/jpg",
 "php" => "text/plain"
 );

 if($mime_type==''){
  $file_extension = strtolower(substr(strrchr($file,"."),1));
  if(array_key_exists($file_extension, $known_mime_types)){
  $mime_type=$known_mime_types[$file_extension];
  } else {
  $mime_type="application/force-download";
  };
 };

 //turn off output buffering to decrease cpu usage
 @ob_end_clean(); 

 // required for IE, otherwise Content-Disposition may be ignored
 if(ini_get('zlib.output_compression'))
  ini_set('zlib.output_compression', 'Off');

 header('Content-Type: ' . $mime_type);
 header('Content-Disposition: attachment; filename="'.$name.'"');
 header("Content-Transfer-Encoding: binary");
 header('Accept-Ranges: bytes');

 /* The three lines below basically make the 
    download non-cacheable */
 header("Cache-control: private");
 header('Pragma: private');
 header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");

 // multipart-download and download resuming support
 if(isset($_SERVER['HTTP_RANGE']))
 {
 list($a, $range) = explode("=",$_SERVER['HTTP_RANGE'],2);
 list($range) = explode(",",$range,2);
 list($range, $range_end) = explode("-", $range);
 $range=intval($range);
 if(!$range_end) {
  $range_end=$size-1;
 } else {
  $range_end=intval($range_end);
 }

 $new_length = $range_end-$range+1;
 header("HTTP/1.1 206 Partial Content");
 header("Content-Length: $new_length");
 header("Content-Range: bytes $range-$range_end/$size");
 } else {
 $new_length=$size;
 header("Content-Length: ".$size);
 }

 /* Will output the file itself */
 $chunksize = 1*(1024*1024); //you may want to change this
 $bytes_send = 0;
 if ($file = fopen($file, 'r'))
 {
 if(isset($_SERVER['HTTP_RANGE']))
 fseek($file, $range);

 while(!feof($file) && 
  (!connection_aborted()) && 
  ($bytes_send<$new_length)
       )
 {
  $buffer = fread($file, $chunksize);
  print($buffer); //echo($buffer); // can also possible
  flush();
  $bytes_send += strlen($buffer);
 }
 fclose($file);
 } else
 //If no permissiion
 die('Error - can not open file.');
 //die
die();
}
//Set the time out
set_time_limit(0);

//path to the file
$file_path=$_SERVER['DOCUMENT_ROOT'].'/your_folder/'.$_REQUEST['filename'];


//Call the download function with file path,file name and file type
output_file($file_path, ''.$_REQUEST['filename'].'', 'text/plain');

?>

Change 'your_folder' with you folder name in both files.

Taryn
  • 242,637
  • 56
  • 362
  • 405
Hardik
  • 1,283
  • 14
  • 34
0

Not with PHP alone. But you should be able to achieve this with some Javascript.

Make the loop from Javascript, creating new frames with the PHP pages as source.

Some browsers would warn their users of multiple file downloads though, but it should work once they accept.

Hope this helps someone searching for an answer.

Nitro Chummy
  • 43
  • 1
  • 8
0

No. The standard only allows for a single file to be downloaded per request. You could, if the ZIP method suggested above is not possible, have a base page with a javascript timeout that redirects the user to each of the files, one at a time. For instance:

<script type="text/javascript">
var file_list = new Array(
  'http://www.mydomain.com/filename1.file',
  'http://www.mydomain.com/filename2.file',
  'http://www.mydomain.com/filename3.file'
);
for (var i=0; i < file_list.length - 1; i++) {
  setTimeout(function () {
     document.location = file_list[i];
  }, i * 1000);
}
</script>

<h1>Please wait</h1>
<p>Your download will start in a moment.</p>
Chris Baker
  • 49,926
  • 12
  • 96
  • 115
  • It's 100% impossible. When changing document location. Java script automatically stopped... –  Feb 28 '14 at 06:47
  • Open them in a new window (using `window.open`), then. If the correct headers are being sent, the new window will close when the file transfer initiates. It is not 100% impossible. – Chris Baker Feb 28 '14 at 08:37