Search code examples
phpcodeigniterzip

Codeigniter ZIP file download corrupted


I Am using the standard CI zip library to read a directory and create a zip file for downloading however when I am testing this in windows I get:

Windows Error

and in OS X the zip unpacks a cpgz file which then unpacks to a zip file - infinitely

My CI function:

public function downloadPackage($unique) {
    $this->load->library('zip');
    $text = $this->syndication_m->getTextForContent($unique);

    $path = '/var/www/html/uploads/'.$unique.'/';

    if(file_exists($path."copy-".$unique.".txt")) {
        unlink($path."copy-".$unique.".txt");
        $fp = fopen($path."copy-".$unique.".txt","wb");
        fwrite($fp,$text);
        fclose($fp);
    }

    $this->zip->read_dir($path);
    $this->zip->download('dl-'.$unique.'.zip');
}

Can anyone help me with a fix or suggest what to do here? Thanks

EDIT

public function downloadPackage($unique) {
    $this->load->library('zip');
    $path = '/var/www/html/uploads/'.$unique.'/';

    $text = $this->syndication_m->getTextForContent($unique);
    $this->zip->read_dir($path, TRUE);
    $this->zip->add_data('copy-'.$unique.'.txt', $text->synd_text);
    $this->zip->download('dl-'.$unique.'.zip');
}

Solution

  • From what i know and what codeigniter's documentation is saying:

    $path = '/var/www/html/uploads/'.$unique.'/';

    • $this->zip->read_dir($path)

      Permits you to compress a folder (and its contents) that already exists somewhere on your server. Supply a file path to the directory and the zip class will recursively read it and recreate it as a Zip archive. All files contained within the supplied path will be encoded, as will any sub-folders contained within it.

    Basically you are creating a zip with everything starting from /var and ending with the files in the $unique folder, something is bound to be wrong ...

    I recommend setting the second parameter to false, as the documentation specifies:

    If you want the tree preceding the target folder to be ignored you can pass FALSE (boolean) in the second parameter.

    • $this->zip->read_dir($path, FALSE)

      This will create a ZIP with the folder "$unique" inside, then all sub-folders stored correctly inside that, but will not include the folders /var/www/html/uploads.

    I also suggest/recommend, for better control of data and i believe fewer resources, to use:

    • $this->zip->add_data() instead of fopen() and $this->zip->read_dir()

    Example:

    public function downloadPackage($unique) {
        $this->load->library('zip');
    
        $text = $this->syndication_m->getTextForContent($unique);
    
        $this->zip->add_data('copy-'.$unique.'.txt', $text);
        $this->zip->download('dl-'.$unique.'.zip');
    }
    

    NOTE: Do not display any data in the controller in which you call this function since it sends various server headers that cause the download to happen and the file to be treated as binary.

    --------------- EDIT ---------------

    Unless you want to add to the zip whatever files are in the $unuqie directory, there is no use for $this->zip->read_dir().

    <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
    
    class Testing extends CI_Controller {
        public function downloadPackage($unique = '') {
            $this->load->library('zip');
    
            $unique = '4ts5yegq;';
            $text = 'I am zorro ...';
    
            $this->zip->add_data('copy-'.$unique.'.txt', $text);
            $this->zip->download('dl-'.$unique.'.zip');
        }
    }