path = $path; $this->fh = fopen($path, 'wb'); if (!$this->fh) throw new RuntimeException("Kann ZIP nicht erstellen: $path"); } public function addFromString(string $localName, string $data): void { $this->addData($localName, $data, time()); } public function addFile(string $filePath, string $localName): void { $data = file_get_contents($filePath); $mtime = filemtime($filePath); $this->addData($localName, $data, $mtime); } private function addData(string $localName, string $data, int $mtime): void { $localName = str_replace('\\', '/', $localName); $crc = crc32($data); $size = strlen($data); $compressed = gzdeflate($data, 6); $compSize = strlen($compressed); // Lokaler Header $dosTime = $this->dosTime(filemtime($filePath)); $nameLen = strlen($localName); $localHeader = pack('VvvvvVVVvv', 0x04034b50, // Signatur 20, // Version needed 0, // Flags 8, // Deflate $dosTime, // Mod time $crc, $compSize, $size, $nameLen, 0 // Extra length ) . $localName; fwrite($this->fh, $localHeader); fwrite($this->fh, $compressed); $this->entries[] = [ 'name' => $localName, 'crc' => $crc, 'size' => $size, 'compSize' => $compSize, 'offset' => $this->offset, 'dosTime' => $dosTime, ]; $this->offset += strlen($localHeader) + $compSize; } public function close(): void { $cdOffset = $this->offset; $cdSize = 0; foreach ($this->entries as $e) { $nameLen = strlen($e['name']); $cd = pack('VvvvvVVVvvvvvVV', 0x02014b50, // CD Signatur 20, // Version made by 20, // Version needed 0, // Flags 8, // Deflate $e['dosTime'], $e['crc'], $e['compSize'], $e['size'], $nameLen, 0, // Extra length 0, // Comment length 0, // Disk start 0, // Internal attr 0, // External attr $e['offset'] ) . $e['name']; fwrite($this->fh, $cd); $cdSize += strlen($cd); } // End of central directory $count = count($this->entries); fwrite($this->fh, pack('VvvvvVVv', 0x06054b50, // EOCD Signatur 0, // Disk number 0, // Disk with CD $count, // Entries on disk $count, // Total entries $cdSize, $cdOffset, 0 // Comment length )); fclose($this->fh); } private function dosTime(int $unixTime): int { $d = getdate($unixTime); return (($d['year'] - 1980) << 25) | ($d['mon'] << 21) | ($d['mday'] << 16) | ($d['hours'] << 11) | ($d['minutes'] << 5) | ($d['seconds'] >> 1); } }