Jump to content
Sign in to follow this  
sww

zipArchive not creating zip file

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;

?>

 

Share this post


Link to post
Share on other sites

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

  • Like 2

Share this post


Link to post
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

Share this post


Link to post
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.

Share this post


Link to post
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.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...