Jump to content

zipArchive not creating zip file


sww
 Share

Recommended Posts

Hey there,

i am knocking my brain out here …

I am trying to generate a zip file based on image paths coming from a url parameter.

Ended up using the zipArchive standard like this way: https://itsolutionstuff.com/post/php-how-to-create-zip-file-and-download-using-ziparchive-example.html.
Also tried this method https://processwire.com/api/ref/wire-file-tools/zip/ before … UNF without any luck on both methods.

All I am getting is a zip file with zero bytes. No errors appear. I think the file isn't even been created in the first place and it is just downloading the defined zip file coming from $fileName

Here is my code:

<?php 

$lb_images = "[".htmlentities($_GET['images'])."]";

// $lb_images = ['/site/assets/files/1062/image-1.jpg','/site/assets/files/1062/image-2.jpg','/site/assets/files/1062/image-3.jpg', ...] 

function createZip($files_ = array(), $destination = '', $overwrite = false) {


   if(file_exists($destination) && !$overwrite) { return false; }


   $validFiles = [];
   if(is_array($files_)) {
      foreach($files_ as $file) {
         if(file_exists($file)) {
            $validFiles[] = $file;
         }
      }
   }


   if(count($validFiles)) {
      $zip = new ZipArchive();
      if($zip->open($destination,$overwrite ? ZIPARCHIVE::OVERWRITE : ZIPARCHIVE::CREATE) !== true) {
         return false;
      }


      foreach($validFiles as $file) {
         $zip->addFile($file,$file);
      }


      $zip->close();
      return file_exists($destination);
   }else{
      return false;
   }

}

$fileName = 'my_zip_'.time().'.zip';
$files_to_zip = $lb_images;
$result = createZip($files_to_zip, $fileName);


header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . $fileName);
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($fileName));
ob_clean();
flush();
readfile($fileName);
exit;

?>

 

Link to comment
Share on other sites

Here's a ProcessWire 3 example. ProcessWire does all the heavy lifting regarding headers, etc. Please see comments in the code and the assumptions made. In this example, we assume a download link is present on the page. Modify the code to suit your needs, if you find it useful :).

<?php namespace ProcessWire;

// @todo: you can add an Array $options parameter to pass to $files->zip()
function createZip($zipfile = '', $filesToZip = array()) {
    // @see: https://processwire.com/api/ref/files/
    $files = wire('files');

    // @todo: error checks here, e.g. if $zipfile (destination) is empty;
    // save zipped files to disk
    // @see: https://processwire.com/api/ref/files/zip/
    $files->zip($zipfile, $filesToZip);
    // force download of zipped files
    // @see: https://processwire.com/api/ref/files/send/
    $files->send($zipfile, array(
        'forceDownload' => true,
        'exit' => false
    ));
    // delete zip file on server after download
    unlink($zipfile);
    exit;
}

$result = array();
$imagesArray = array();
$zipImages = array();

// grab and sanitize image names string in $_GET parameter 'images'
// in this example, names are comma-separated
$images = $sanitizer->entities($input->get->images);

// if we have a 'get' input
if($images) {
    // create array of image names (array('image-1.jpg', 'image2.jpg')) etc
    $imagesArray = explode(',', $images);
    // sanitize each image name as per ProcessWire filename expectations
    $imagesArray = $sanitizer->array($imagesArray, 'filename');
    // if we got an array of sanitized image names
    if(count($imagesArray)) {
        // get the image repository
        // in this example, we store all images in one page in...
        // ... an image field named 'images'
        $imagesPage = $pages->get("/zip-files/zip-file-images/");
        // create selector to find images requested in $_GET
        // this example assumes $_GET parameter 'images' contains image basenames
        // @note: we make sure image names are lowercase
        // selector: "basename=image-1.jpg|image2.jpg"
        $imagesSelector = mb_strtolower(implode('|', $imagesArray));

        $images = $imagesPage->images->find("basename={$imagesSelector}");

        // if we got a match
        if($images->count) {
            // create array of full disk paths to the image files
            $zipImages = $images->explode('filename');
            // just making sure we got an array back
            if(count($zipImages)) {
                // name of zip file to create (or update)
                $zipfile = $config->paths->assets . "my_zip_".time().".zip";
                // create zip file + force download
                //$result = createZip($zipfile, $zipImages);
                createZip($zipfile, $zipImages);
            }
            
        }
      
    }
}

// assuming $_GET will contain image basenames
$downloadImagesLink = "/zip-files/zip-file-test/?images=abstract.jpg,Tree-Wide.jpg,fashion.jpg,dessert.jpg,citrus_fun.jpg";

?>

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta http-equiv="content-type" content="text/html; charset=utf-8" />
		<title><?php echo $page->title; ?></title>
		<link rel="stylesheet" type="text/css" href="<?php echo $config->urls->templates?>styles/main.css" />
	</head>
	<body>
		<h1><?php echo $page->title; ?></h1>
        <?php 
            $out = "<p>Download Zipped Images</p>";
            $out .= "<p><a href='{$downloadImagesLink}'>Click to download</a></p>";
            echo $out;		
		?>	
	</body>
</html>

 

  • Like 5
Link to comment
Share on other sites

9 hours ago, tpr said:

My guess is that you would need to supply full absolute paths instead relative ones. 

tried full path too …

6 hours ago, kongondo said:

Here's a ProcessWire 3 example. ProcessWire does all the heavy lifting regarding headers, etc. Please see comments in the code and the assumptions made. In this example, we assume a download link is present on the page. Modify the code to suit your needs, if you find it useful :).


<?php namespace ProcessWire;

// @todo: you can add an Array $options parameter to pass to $files->zip()
function createZip($zipfile = '', $filesToZip = array()) {
    // @see: https://processwire.com/api/ref/files/
    $files = wire('files');

    // @todo: error checks here, e.g. if $zipfile (destination) is empty;
    // save zipped files to disk
    // @see: https://processwire.com/api/ref/files/zip/
    $files->zip($zipfile, $filesToZip);
    // force download of zipped files
    // @see: https://processwire.com/api/ref/files/send/
    $files->send($zipfile, array(
        'forceDownload' => true,
        'exit' => false
    ));
    // delete zip file on server after download
    unlink($zipfile);
    exit;
}

$result = array();
$imagesArray = array();
$zipImages = array();

// grab and sanitize image names string in $_GET parameter 'images'
// in this example, names are comma-separated
$images = $sanitizer->entities($input->get->images);

// if we have a 'get' input
if($images) {
    // create array of image names (array('image-1.jpg', 'image2.jpg')) etc
    $imagesArray = explode(',', $images);
    // sanitize each image name as per ProcessWire filename expectations
    $imagesArray = $sanitizer->array($imagesArray, 'filename');
    // if we got an array of sanitized image names
    if(count($imagesArray)) {
        // get the image repository
        // in this example, we store all images in one page in...
        // ... an image field named 'images'
        $imagesPage = $pages->get("/zip-files/zip-file-images/");
        // create selector to find images requested in $_GET
        // this example assumes $_GET parameter 'images' contains image basenames
        // @note: we make sure image names are lowercase
        // selector: "basename=image-1.jpg|image2.jpg"
        $imagesSelector = mb_strtolower(implode('|', $imagesArray));

        $images = $imagesPage->images->find("basename={$imagesSelector}");

        // if we got a match
        if($images->count) {
            // create array of full disk paths to the image files
            $zipImages = $images->explode('filename');
            // just making sure we got an array back
            if(count($zipImages)) {
                // name of zip file to create (or update)
                $zipfile = $config->paths->assets . "my_zip_".time().".zip";
                // create zip file + force download
                //$result = createZip($zipfile, $zipImages);
                createZip($zipfile, $zipImages);
            }
            
        }
      
    }
}

// assuming $_GET will contain image basenames
$downloadImagesLink = "/zip-files/zip-file-test/?images=abstract.jpg,Tree-Wide.jpg,fashion.jpg,dessert.jpg,citrus_fun.jpg";

?>

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta http-equiv="content-type" content="text/html; charset=utf-8" />
		<title><?php echo $page->title; ?></title>
		<link rel="stylesheet" type="text/css" href="<?php echo $config->urls->templates?>styles/main.css" />
	</head>
	<body>
		<h1><?php echo $page->title; ?></h1>
        <?php 
            $out = "<p>Download Zipped Images</p>";
            $out .= "<p><a href='{$downloadImagesLink}'>Click to download</a></p>";
            echo $out;		
		?>	
	</body>
</html>

 

thanks … will try it out asap.

Link to comment
Share on other sites

@tpr @kongondo thanks again. 

but i took a second thought on that. for my purpose it's better the visitor gets a designed pdf having all the images in place instead of getting them as single files to their download folder. so i ended up using the fpdf library … works like a charm.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...