Richie: zip - on the fly

Hallo zusammen,

ich möchte 'on the fly' mehrer Dateien in einem zip archive speichern.
Habe eine passende Klasse bei Zend gefunden:
http://www.zend.com/codex.php?id=696&single=1

Leider wird bei meiner Umsetzung nur ein leeres zip archive generiert.
Die zu packende Datei datei.txt ist im gleichen Verzeichnis wie das Script.

Kann jemand vielleicht einen Fehler entdecken?
OS=Suse web-edition 7

<?php
class zipfile
{

var $datasec = array(); // array to store compressed data
    var $ctrl_dir = array(); // central directory
    var $eof_ctrl_dir = "x50x4bx05x06x00x00x00x00"; //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 = "x50x4bx03x04";
        $fr .= "x0ax00";    // ver needed to extract
        $fr .= "x00x00";    // gen purpose bit flag
        $fr .= "x00x00";    // compression method
        $fr .= "x00x00x00x00"; // 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 http://support.microsoft.com/support/kb/articles/Q125/0/19.asp

// now add to central record
        $cdrec = "x50x4bx01x02";
        $cdrec .="x00x00";    // version made by
        $cdrec .="x0ax00";    // version needed to extract
        $cdrec .="x00x00";    // gen purpose bit flag
        $cdrec .="x00x00";    // compression method
        $cdrec .="x00x00x00x00"; // 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 = "x00x00x10x00";
        $ext = "xffxffxffxff";
        $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;
        $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

{
        $name = str_replace("", "/", $name);
        //$name = str_replace("", "", $name);

$fr = "x50x4bx03x04";
        $fr .= "x14x00";    // ver needed to extract
        $fr .= "x00x00";    // gen purpose bit flag
        $fr .= "x08x00";    // compression method
        $fr .= "x00x00x00x00"; // 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 = "x50x4bx01x02";
        $cdrec .="x00x00";    // version made by
        $cdrec .="x14x00";    // version needed to extract
        $cdrec .="x00x00";    // gen purpose bit flag
        $cdrec .="x08x00";    // compression method
        $cdrec .="x00x00x00x00"; // 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
//        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
            "x00x00";                             // .zip file comment length
    }
}

$zipfile = new zipfile();
// add the subdirectory ... important!
$direc="datei/";
$zipfile -> add_dir($direc);
// add the binary data stored in the string 'filedata'
$path="./datei.txt";

if(is_file($path)) {
   $fp = fopen ($path, "rb") or die("fehler01");
   $filedata = fread ($fp, filesize($path));
   $zipfile -> add_file($filedata, "datei/datei.txt") or die("fehler02");
   fclose($fp);

}else{
                           die("nofile");
                         }

// the next three lines force an immediate download of the zip file:
header("Content-type: application/octet-stream");
header("Content-disposition: attachment; filename=output.zip");
$zipfile -> file();
?>
Gruß Richie

  1. Lieber Richie,

    Die zu packende Datei datei.txt ist im gleichen Verzeichnis wie das Script.
    // add the subdirectory ... important!
    $direc="datei/";
       $zipfile -> add_file($filedata, "datei/datei.txt") or die("fehler02");

    Jetzt klar?

    Liebe Grüße aus Ellwangen,

    Felix Riesterer.

    1. Tach Felix,

      habe ich auch mit einem Verzeichnis datei/datei.txt als AusgangsVerzeichnis versucht. Geht auch nicht. Der zweite Parameter gibt den Pfad zum Speicherort im Zip-Archive an. Dieser Ordner datei/ wird von add_dir() angelegt.

      Das ist es leider nicht.

      Ich habe wirklich schon sehr viel einfach nur rumprobiert(mangels Wissen).

      Gruß

      Lieber Richie,

      Die zu packende Datei datei.txt ist im gleichen Verzeichnis wie das Script.
      // add the subdirectory ... important!
      $direc="datei/";
         $zipfile -> add_file($filedata, "datei/datei.txt") or die("fehler02");

      Jetzt klar?

      Liebe Grüße aus Ellwangen,

      Felix Riesterer.

      1. Hallo Leute,

        die beste Lösung füe zip on the fly unter Beibehaltung der Ordnerstruktur findet Ihr unter http://smiledsoft.com/demos/phpzip/

        Gruß Richie

        1. Hi,

          die beste Lösung füe zip on the fly unter Beibehaltung der Ordnerstruktur findet Ihr unter http://smiledsoft.com/demos/phpzip/

          Die Pro-Version kostet Geld, und die freie Variante ist nicht die Beste.

          Aber trotzdem danke: Die Pro bietet nette Anregungen, die es nunmehr sicherlich auch mal kostenlos geben wird. ;-)

          Gruß, Cybaer

          --
          Hinweis an Fragesteller: Fremde haben ihre Freizeit geopfert, um Dir zu helfen. Helfe Du auch im Archiv Suchenden: Beende deinen Thread mit einem "Hat geholfen" oder "Hat nicht geholfen"!
  2. Hallo Richie,

    Habe eine passende Klasse bei Zend gefunden:
    http://www.zend.com/codex.php?id=696&single=1

    Mit dieser Klasse bin ich nicht weit gekommen (es hat erstmal Notices gehagelt) - aber da mich das auch interessiert hat, habe ich mal etwas weiter gesucht und bin bei phpMyAdmin fündig geworden. In dessen Unterverzeichnis "libaries" gibt es eine Datei namens zip.lib.php, die die von dir gepostete Klasse enthält, allerdings mit ein paar Verbesserungen. Mit dem anhand des Codes aus <pma-verzeichnis>/export.php (und den headern aus einem eigenen Projekt) habe ich dann diesen Codeschnippsel zusammengebastelt:

    require_once('zip.lib.php');  
    $zipfile = new zipfile();  
    $zipfile -> addFile('foobar', 'datei.txt');  
    $dump_buffer = $zipfile->file();  
    header('Content-Type: application/zip');  
    header('Content-Length: '.strlen($dump_buffer));  
    header('Content-Disposition: attachment; filename="test.zip"');  
    echo $dump_buffer;  
    exit;
    

    damit wird eine zip-Datei erzeugt, die eine Datei namens "datei.txt"( mit dem Inhalt "foobar") enthält.

    Grüße aus Nürnberg
    Tobias

  3. Hi,

    ich möchte 'on the fly' mehrer Dateien in einem zip archive speichern.
    Habe eine passende Klasse bei Zend gefunden:

    Basierend auf dieser Klasse habe ich ebenfalls einen "ZIPper" geschrieben:

    ZIP mit PHP (Klasse mit notwendigen Unterfunktionen)

    $z=new ZIParchive();
    $result=$z->zip(array('/dir1/datei1','/dir2/datei2'),'/archiv.zip');

    packt datei1 & datei2 in ein Archiv /archiv.zip

    Auch gibt es bereits einen (noch nicht fertigen) "Nachfolger": ZIP mit PHP 2 (nur die Klasse ohne Unterfunktionen)

    $z=new ZIParchive();
    $result=$z->zip(array('/dir1/datei1','/dir2/datei2'),'%DOWNLOAD%/archiv.zip');

    Dabei wird das Archiv archiv.zip nicht erstellt (wohl aber ein bereits vorhandenes erweitert), sondern direkt als Download übergeben. Hierbei kann z.B. auch eingestellt werden, daß das zippende Script selbst nicht mit eingepackt wird.

    Gruß, Cybaer

    --
    Hinweis an Fragesteller: Fremde haben ihre Freizeit geopfert, um Dir zu helfen. Helfe Du auch im Archiv Suchenden: Beende deinen Thread mit einem "Hat geholfen" oder "Hat nicht geholfen"!