Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations John Tel on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Download multiple image files from server to client's machine

Status
Not open for further replies.

tewari68

Programmer
Jan 25, 2005
87
US
Hi,
I have to provide a functionality where my clients can browse images folder on my server and select multiple images to download on their computer.
Could be done by http request and zipping the files.
I would appreciate if anybody can guide me how to create the zip file and point to any site which has a readymade script for zipping the files before download in PHP.
My code so far is
Code:
 <?

     $HOST="abc.com";
     $UN="xyz";
     $PW="zyx";
     $DIR="/images/";
     //$FILE="test.txt";

     $conn = ftp_connect($HOST);
     if(!$conn) {
        exit("Could not connect to server: $HOST\n");
    }

    if(!ftp_login($conn,$UN,$PW)) {

        ftp_quit($conn);
        exit("Could not log in\n");
    }
	ftp_chdir($conn,$DIR);


 if($_POST['download'] != '')
 {
	 
foreach ($_POST['filearrayname'] as $key=>$val)
	 {
      [COLOR=#ff0000] //some code here to create a zip file which has all the selected image files[/color]

   $newDirectory = "downloaded";

   	$movefiles =  "mv ".$val." ".$newDirectory;
	system($movefiles);

	 }
//making the zip file available for download

   header('Content-type: application/octet-stream');
   header('Content-Disposition: attachment;filename=x.zip');
   //readfile($val);	

	 unset($_POST['submit']);
ftp_quit($conn);
 }
     
    
   

    $files = ftp_nlist($conn,".");
?>
<form name = "ftpupdown" action = <? echo $PHP_SELF ?> method = "post"> <table>
<?
    for($i=0;$i<count($files);$i++) {
		if($files[$i] != "." || $files[$i] != "..")
	{
		echo "<tr><td><input type = radio name = filearrayname[".$files[$i] ."] value=".$files[$i].">".$files[$i]."</td></tr>";
	}
		//if(!ftp_get($conn,$files[$i],$files[$i],FTP_ASCII)) {
          //  echo "Could not download {$files[$i]}\n";
        //}
    }
?>
<tr><td> <input type = "submit" name="download" value = "Start Download"></td></tr></table></form>
<?

    //if(!ftp_put($conn,$DIR.$FILE,$FILE,FTP_ASCII)) {
      //  echo "Could not upload $FILE\n";
   // }

    //ftp_quit($conn);
    ?>

Appreciate any help.
Thanks,
Tewari.
 
Hi sleipnir214,
I tried using the example as suggested it generates a test.zip file can I change the name to something else and also when I try opening the file the following error message is thrown up -
The archive is either in unknown format or damaged.
I try to open it using winzip.

Appreciate if you can suggest some changes.
the modified code is as follows
Code:
 <?
 require_once ("zipfile.php");[COLOR=#ff0000]=> zip class[/color]
     $HOST="abc.com";
     $UN="xyz";
     $PW="zxy";
     $DIR="/images/";
     $FILE="test.txt";

     $conn = ftp_connect($HOST);
     if(!$conn) {
        exit("Could not connect to server: $HOST\n");
    }

    if(!ftp_login($conn,$UN,$PW)) {

        ftp_quit($conn);
        exit("Could not log in\n");
    }
	ftp_chdir($conn,$DIR);


 if($_POST['download'] != '')
 {
	 $zipfile = new zipfile();  
foreach ($_POST['filearrayname'] as $key=>$val)
	 {
       $handle = fopen("/images/".$val, "r");
      $contents = fread($handle, filesize("/images/".$val));
     fclose($handle);
	 $zipfile -> add_file($contents, $val);  

   $newDirectory = "downloaded";

   	$movefiles =  "mv ".$val." ".$newDirectory;
	system($movefiles);

echo $key."=>".$val;
//$download_dir = "C:\\".$_POST['downloaddir']."\\".$val;
//echo $download_dir;
//exit;
//if(!ftp_get($conn,$download_dir,$val,FTP_ASCII)) {
  //          echo "Could not download {$files[$i]}\n";
//}
//else
//		 {
//	echo "Files downloaded".$val;
//		 }
//ftp_quit($conn);
	 }
   header('Content-type: application/octet-stream');
   header('Content-Disposition: attachment;filename=test.zip');
   //readfile($val);	

	 unset($_POST['submit']);
 }
     
    
   

    $files = ftp_nlist($conn,".");
?>
<form name = "ftpupdown" action = <? echo $PHP_SELF ?> method = "post"> <table>
<?
    for($i=0;$i<count($files);$i++) {
		if($files[$i] != "." || $files[$i] != "..")
	{
		echo "<tr><td><input type = radio name = filearrayname[".$files[$i] ."] value=".$files[$i].">".$files[$i]."</td></tr>";
	}
		//if(!ftp_get($conn,$files[$i],$files[$i],FTP_ASCII)) {
          //  echo "Could not download {$files[$i]}\n";
        //}
    }
?>
<tr><td>Please specify the directory name where to download the files<br>C:\&nbsp;&nbsp<input type=text name=downloaddir value=''></td></tr>
<tr><td> <input type = "submit" name="download" value = "Start Download"></td></tr></table></form>
<?

    //if(!ftp_put($conn,$DIR.$FILE,$FILE,FTP_ASCII)) {
      //  echo "Could not upload $FILE\n";
   // }

    //ftp_quit($conn);
    ?>
 
t generates a test.zip file can I change the name to something else
Do you mean the filename you set in the following line of your code?

[tt]header('Content-Disposition: attachment;filename=test.zip');[/tt]

? <facetious>No, you're stuck with whatever you've typed there.</facetious>


hen I try opening the file the following error message is thrown up -
The archive is either in unknown format or damaged.
Insufficient data for a meaningful answer. All your zipfile manipulation code is built into a class file, zipfile.php, which I know nothing about.



Want the best answers? Ask the best questions! TANSTAAFL!
 
Hi,
Sorry I missed posting the zip class file.

Here is the zip class file, I got from the web
[/code]
<?php

/*

Zip file creation class
makes zip files on the fly...

use the functions add_dir() and add_file() to build the zip file;
see example code below

by Eric Mueller

v1.1 9-20-01
- added comments to example

v1.0 2-5-01

initial version with:
- class appearance
- add_file() and file() methods
- gzcompress() output hacking
by Denis O.Philippov, webmaster@atlant.ru,
*/
// official ZIP file format: // pkware.com/appnote.txt

class zipfile
{

var $datasec = array(); // array to store compressed data
var $ctrl_dir = array(); // central directory
var $eof_ctrl_dir = "\x50\x4b\x05\x06\x00\x00\x00\x00"; //end of Central directory record
var $old_offset = 0;

function add_dir($name)

// adds "directory" to archive - do this before putting any files in directory!
// $name - name of directory... like this: "path/"
// ...then you can add files using add_file with names like "path/file.txt"
{
$name = str_replace("\\", "/", $name);

$fr = "\x50\x4b\x03\x04";
$fr .= "\x0a\x00"; // ver needed to extract
$fr .= "\x00\x00"; // gen purpose bit flag
$fr .= "\x00\x00"; // compression method
$fr .= "\x00\x00\x00\x00"; // last mod time and date

$fr .= pack("V",0); // crc32
$fr .= pack("V",0); //compressed filesize
$fr .= pack("V",0); //uncompressed filesize
$fr .= pack("v", strlen($name) ); //length of pathname
$fr .= pack("v", 0 ); //extra field length
$fr .= $name;
// end of "local file header" segment

// no "file data" segment for path

// "data descriptor" segment (optional but necessary if archive is not served as file)
$fr .= pack("V",$crc); //crc32
$fr .= pack("V",$c_len); //compressed filesize
$fr .= pack("V",$unc_len); //uncompressed filesize

// add this entry to array
$this -> datasec[] = $fr;

$new_offset = strlen(implode("", $this->datasec));

// ext. file attributes mirrors MS-DOS directory attr byte, detailed
// at

// now add to central record
$cdrec = "\x50\x4b\x01\x02";
$cdrec .="\x00\x00"; // version made by
$cdrec .="\x0a\x00"; // version needed to extract
$cdrec .="\x00\x00"; // gen purpose bit flag
$cdrec .="\x00\x00"; // compression method
$cdrec .="\x00\x00\x00\x00"; // last mod time & date
$cdrec .= pack("V",0); // crc32
$cdrec .= pack("V",0); //compressed filesize
$cdrec .= pack("V",0); //uncompressed filesize
$cdrec .= pack("v", strlen($name) ); //length of filename
$cdrec .= pack("v", 0 ); //extra field length
$cdrec .= pack("v", 0 ); //file comment length
$cdrec .= pack("v", 0 ); //disk number start
$cdrec .= pack("v", 0 ); //internal file attributes
$ext = "\x00\x00\x10\x00";
$ext = "\xff\xff\xff\xff";
$cdrec .= pack("V", 16 ); //external file attributes - 'directory' bit set

$cdrec .= pack("V", $this -> old_offset ); //relative offset of local header
$this -> old_offset = $new_offset;

$cdrec .= $name;
// optional extra field, file comment goes here
// save to array
$this -> ctrl_dir[] = $cdrec;


}


function add_file($data, $name)

// adds "file" to archive
// $data - file contents
// $name - name of file in archive. Add path if your want

{
$fp=fopen($data,"r");
$data=fread($fp,filesize($data));
fclose($fp);

//$data = str_replace("\x0a", "\x0d\x0a", $data);
$name = str_replace("\\", "/", $name);
//$name = str_replace("\\", "\\\\", $name);

$fr = "\x50\x4b\x03\x04";
$fr .= "\x14\x00"; // ver needed to extract
$fr .= "\x00\x00"; // gen purpose bit flag
$fr .= "\x08\x00"; // compression method
$fr .= "\x00\x00\x00\x00"; // last mod time and date

$unc_len = strlen($data);
$crc = crc32($data);
$zdata = gzcompress($data);
$zdata = substr( substr($zdata, 0, strlen($zdata) - 4), 2); // fix crc bug
$c_len = strlen($zdata);
$fr .= pack("V",$crc); // crc32
$fr .= pack("V",$c_len); //compressed filesize
$fr .= pack("V",$unc_len); //uncompressed filesize
$fr .= pack("v", strlen($name) ); //length of filename
$fr .= pack("v", 0 ); //extra field length
$fr .= $name;
// end of "local file header" segment

// "file data" segment
$fr .= $zdata;

// "data descriptor" segment (optional but necessary if archive is not served as file)
$fr .= pack("V",$crc); //crc32
$fr .= pack("V",$c_len); //compressed filesize
$fr .= pack("V",$unc_len); //uncompressed filesize

// add this entry to array
$this -> datasec[] = $fr;

$new_offset = strlen(implode("", $this->datasec));

// now add to central directory record
$cdrec = "\x50\x4b\x01\x02";
$cdrec .="\x00\x00"; // version made by
$cdrec .="\x14\x00"; // version needed to extract
$cdrec .="\x00\x00"; // gen purpose bit flag
$cdrec .="\x08\x00"; // compression method
$cdrec .="\x00\x00\x00\x00"; // last mod time & date
$cdrec .= pack("V",$crc); // crc32
$cdrec .= pack("V",$c_len); //compressed filesize
$cdrec .= pack("V",$unc_len); //uncompressed filesize
$cdrec .= pack("v", strlen($name) ); //length of filename
$cdrec .= pack("v", 0 ); //extra field length
$cdrec .= pack("v", 0 ); //file comment length
$cdrec .= pack("v", 0 ); //disk number start
$cdrec .= pack("v", 0 ); //internal file attributes
$cdrec .= pack("V", 32 ); //external file attributes - 'archive' bit set

$cdrec .= pack("V", $this -> old_offset ); //relative offset of local header
// &n // bsp; echo "old offset is ".$this->old_offset.", new offset is $new_offset<br>";
$this -> old_offset = $new_offset;

$cdrec .= $name;
// optional extra field, file comment goes here
// save to central directory
$this -> ctrl_dir[] = $cdrec;
}

function file() { // dump out file
$data = implode("", $this -> datasec);
$ctrldir = implode("", $this -> ctrl_dir);

return
$data.
$ctrldir.
$this -> eof_ctrl_dir.
pack("v", sizeof($this -> ctrl_dir)). // total # of entries "on this disk"
pack("v", sizeof($this -> ctrl_dir)). // total # of entries overall
pack("V", strlen($ctrldir)). // size of central dir
pack("V", strlen($data)). // offset to start of central dir
"\x00\x00"; // .zip file comment length
}
}

?>
[/code]
 
i reckon there should be a way of downloading multiple files without using zip or gzip.

i've never tried this but you might consider using a multipart header and an overall header that supports MIME encoding.

the key to this will be finding an overall header content type that supports mime encoding and multipart and that is itself supported by the main browsers. I'd guess "message" for the overall Content type and then use application/octet-stream for each internal boundary.

multipart/mixed is not supported in IE or firefox (sfaik) but i dimly remember reading that "message" is more widely supported.

and ... you can always send the files by email.
 
The more I look at it, the more I don't like the options in the manual.

A much simpler option is to use O.S. commands to create the file. I notice your use of forwardslashes in some of your path- and file-name strings, so I'm going to assume you're running PHP on a unix-like O.S.

On my Linux box, the following creates the zip archive using the external command [tt]zip[/tt] and sends it to the browser. The "images" directory is assumed to be a subdirectory of the one in which the script lies:

Code:
<?php
header('Content-type: application/octet-stream');
header('Content-Disposition: attachment;filename=test.zip');

$command = '/usr/bin/zip - images/image1.jpg images/ image2.jpg images/new_image.jpg';
//the bare dash (" - ") in the command-string tells the zip
//command to send the zip file out on stdout, which is
//perfect for streaming to a browser

$handle = popen ($command, 'r');

fpassthru($handle);
?>



Want the best answers? Ask the best questions! TANSTAAFL!
 
Hi Sleipnir214,
Tried your code today, your code workes perfectly. I can download the zip file and unzip it under unix, however when I try to unzip the files using winzip on a windows machine I get the following error mesg - start of central directory not found, zip file corrupt.

Is there any other options that we need to use while zipping the files under unix to make the zip file compatible with windows.

Appreciate any help in this regards.
Thanks,
tewari
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top