Welcome Guest, Not a member yet? Register   Sign In
CI Zip Library
#1

[eluser]John Ashwin[/eluser]
Hiya,

Well, this is a problem I faced a few days back, and
this is the simple fix that i used. It is actually
a mod of this extension for a different zip class:
tutorial-create-a-zip-file-from-folders-on-the-fly

It was a frustrating problem, and I hope this will help someone else.


When zipping up a folder outside my root like
eg:

Code:
$path = '/path/to/your/directory/';
$this->zip->read_dir($path);
$this->zip->download('my_backup.zip');

The resulting zip file had the same structure
eg: my_backup.zip/path/to/your/directory/

This simple extension of the Zip library allows me to get files from a deep
folder and rename the structure in the Zip.

Usage:
Code:
$path = '/path/to/your/directory/';
$folder_in_zip = "source-code";

$this->zip->add_dir($folder_in_zip);  // Create folder in zip
$this->zip->get_files_from_folder($path, $folder_in_zip);

$this->zip->download('my_backup.zip');
Resulting Zip:
mybackup.zip/source-code/(contents and inner of $path)

Code:
// MY_Zip.php
<?php
class MY_Zip extends CI_Zip
{
    function MY_Zip()
    {
        parent::CI_Zip();
        
    }
    
    
    function get_files_from_folder($directory, $put_into) {
            if ($handle = opendir($directory)) {
                while (false !== ($file = readdir($handle))) {
                    if (is_file($directory.$file)) {
                        $fileContents = file_get_contents($directory.$file);
                        
                        $this->add_data($put_into.$file, $fileContents);
                        
                    } elseif ($file != '.' and $file != '..' and is_dir($directory.$file)) {
                        
                        $this->add_dir($put_into.$file.'/');
                        
                        $this->get_files_from_folder($directory.$file.'/', $put_into.$file.'/');
                    }
                }
            }
            closedir($handle);
    }
        
}
?>



Do post your suggestions or if there are other better solutions. Smile

Cheers,
John Ashwin
#2

[eluser]louis w[/eluser]
Thanks for the post. I REALLY think Ellis Labs needs to roll something like this into the zip library. Keeping the full server directory path is quite annoying - especially with client facing sites.

Also, because your not doing anything in the constructor, you don't need to have it in your extended class. This can be removed:

Code:
function MY_Zip()
    {
        parent::CI_Zip();
        
    }
#3

[eluser]louis w[/eluser]
After testing this out, I didn't like how the data inside the folder I was trying to add still needed to be inside a directory in the archive. I checked out the CI read_dir call, a couple small changes you can call read_dir to create an archive containing all the files without any directories. Even works with nested folders.

Code:
class MY_Zip extends CI_Zip {

    function read_dir($path, $base=null) {    
    
        if (is_null($base)) $base = $path;

        if ($fp = @opendir($path)) {

            while (FALSE !== ($file = readdir($fp))) {

                if (@is_dir($path.$file) && substr($file, 0, 1) != '.') {    
                    $this->read_dir($path.$file."/", $base);
                } else if (substr($file, 0, 1) != ".") {
                    if (FALSE !== ($data = file_get_contents($path.$file))) {                        
                        $file_name = ltrim($path.$file, $base);
                        $this->add_data($file_name, $data);
                    }
                }
            }

            return TRUE;

        }
    }
        
}
#4

[eluser]John Ashwin[/eluser]
Thanks man.. Smile

I've included your function into the extension. It will come in very useful
for for an upcoming project.

There's another mod as well. Empty timestamps were causing notepad++ and sourceDiff
to crash on me. lol.. It seems winrar and stuffit don't handle missing timestamps
very well, during extraction.

This is the excerpt. The full code is in the attachment.


Code:
/**
     * Mod by : John Christos
     * Add Data to Zip With Dates To Correct no timestamp when
     * extracted by winrar and stuffIt.
     *
     * The extracted files with no timestamp crashed sourceDiff & Notepad++
     * on my system.
     *
     * This fix forces the files to have a timestamp.
     *
     * @access    private
     * @param    string    the file name/path
     * @param    string    the data to be encoded
     * @return    void
     */    
    function _add_data($filepath, $data, $time = 0)
    {
        $filepath = str_replace("\\", "/", $filepath);
        
        // Create TimeStamp
        $dtime    = dechex($this->unix2DosTime($time));

        $hexdtime = '\x' . $dtime[6] . $dtime[7]
                  . '\x' . $dtime[4] . $dtime[5]
                  . '\x' . $dtime[2] . $dtime[3]
                  . '\x' . $dtime[0] . $dtime[1];
                  
        eval('$hexdtime = "' . $hexdtime . '";');
        
        // At this point the Timestamp is in $hexdtime;
        
        

        $uncompressed_size = strlen($data);
        $crc32  = crc32($data);

        $gzdata = gzcompress($data);
        $gzdata = substr($gzdata, 2, -4);
        $compressed_size = strlen($gzdata);
        
    $this->zipdata .=
            "\x50\x4b\x03\x04\x14\x00\x00\x00\x08\x00" . $hexdtime
            .pack('V', $crc32)
            .pack('V', $compressed_size)
            .pack('V', $uncompressed_size)
            .pack('v', strlen($filepath)) // length of filename
            .pack('v', 0) // extra field length
            .$filepath
            .$gzdata; // "file data" segment
            
            

        $this->directory .=
            "\x50\x4b\x01\x02\x00\x00\x14\x00\x00\x00\x08\x00\x00\x00\x00\x00"
            .pack('V', $crc32)
            .pack('V', $compressed_size)
            .pack('V', $uncompressed_size)
            .pack('v', strlen($filepath)) // length of filename
            .pack('v', 0) // extra field length
            .pack('v', 0) // file comment length
            .pack('v', 0) // disk number start
            .pack('v', 0) // internal file attributes
            .pack('V', 32) // external file attributes - 'archive' bit set
            .pack('V', $this->offset) // relative offset of local header
            .$filepath;

        $this->offset = strlen($this->zipdata);
        $this->entries++;
        $this->file_num++;
    }
    
    // --------------------------------------------------------------------
    
    
    /**
     * (This function is borrowed from http://drupal.org/node/83253)
     * Converts an Unix timestamp to a four byte DOS date and time format (date
     * in high two bytes, time in low two bytes allowing magnitude comparison).
     *
     * @param  integer  the current Unix timestamp
     *
     * @return integer  the current date in a four byte DOS format
     *
     * @access private
     */
    function unix2DosTime($unixtime = 0) {
        $timearray = ($unixtime == 0) ? getdate() : getdate($unixtime);

        if ($timearray['year'] < 1980) {
            $timearray['year']    = 1980;
            $timearray['mon']     = 1;
            $timearray['mday']    = 1;
            $timearray['hours']   = 0;
            $timearray['minutes'] = 0;
            $timearray['seconds'] = 0;
        } // end if

        return (($timearray['year'] - 1980) << 25) | ($timearray['mon'] << 21) | ($timearray['mday'] << 16) |
                ($timearray['hours'] << 11) | ($timearray['minutes'] << 5) | ($timearray['seconds'] >> 1);
    } // end of the 'unix2DosTime()' method
#5

[eluser]Techno Heart[/eluser]
Thanks a lot Dude.. Very useful post




Theme © iAndrew 2016 - Forum software by © MyBB