1*1729dd47SHenrik Yllemo<?php 2*1729dd47SHenrik Yllemo/** 3*1729dd47SHenrik Yllemo * Minimal ZIP writer using the STORE method only. 4*1729dd47SHenrik Yllemo * This avoids requiring ext-zip or PclZip. Suitable for generated Markdown packages. 5*1729dd47SHenrik Yllemo */ 6*1729dd47SHenrik Yllemoclass SkillForge_StoredZipWriter { 7*1729dd47SHenrik Yllemo private $entries = array(); 8*1729dd47SHenrik Yllemo 9*1729dd47SHenrik Yllemo public function addFileFromString($path, $data) { 10*1729dd47SHenrik Yllemo $path = str_replace('\\', '/', trim($path, '/')); 11*1729dd47SHenrik Yllemo if ($path === '') return; 12*1729dd47SHenrik Yllemo $this->entries[] = array('path' => $path, 'data' => (string)$data); 13*1729dd47SHenrik Yllemo } 14*1729dd47SHenrik Yllemo 15*1729dd47SHenrik Yllemo public function addFile($pathInZip, $filePath) { 16*1729dd47SHenrik Yllemo if (is_readable($filePath)) { 17*1729dd47SHenrik Yllemo $this->addFileFromString($pathInZip, file_get_contents($filePath)); 18*1729dd47SHenrik Yllemo } 19*1729dd47SHenrik Yllemo } 20*1729dd47SHenrik Yllemo 21*1729dd47SHenrik Yllemo public function save($targetFile) { 22*1729dd47SHenrik Yllemo $fh = fopen($targetFile, 'wb'); 23*1729dd47SHenrik Yllemo if (!$fh) return false; 24*1729dd47SHenrik Yllemo 25*1729dd47SHenrik Yllemo $central = ''; 26*1729dd47SHenrik Yllemo $offset = 0; 27*1729dd47SHenrik Yllemo 28*1729dd47SHenrik Yllemo foreach ($this->entries as $entry) { 29*1729dd47SHenrik Yllemo $name = $entry['path']; 30*1729dd47SHenrik Yllemo $data = $entry['data']; 31*1729dd47SHenrik Yllemo $crc = crc32($data); 32*1729dd47SHenrik Yllemo if ($crc < 0) $crc += 4294967296; 33*1729dd47SHenrik Yllemo $size = strlen($data); 34*1729dd47SHenrik Yllemo list($time, $date) = $this->dosDateTime(); 35*1729dd47SHenrik Yllemo 36*1729dd47SHenrik Yllemo $local = "PK\x03\x04"; 37*1729dd47SHenrik Yllemo $local .= pack('v', 20); // version needed 38*1729dd47SHenrik Yllemo $local .= pack('v', 0); // flags 39*1729dd47SHenrik Yllemo $local .= pack('v', 0); // compression: store 40*1729dd47SHenrik Yllemo $local .= pack('v', $time); 41*1729dd47SHenrik Yllemo $local .= pack('v', $date); 42*1729dd47SHenrik Yllemo $local .= pack('V', $crc); 43*1729dd47SHenrik Yllemo $local .= pack('V', $size); 44*1729dd47SHenrik Yllemo $local .= pack('V', $size); 45*1729dd47SHenrik Yllemo $local .= pack('v', strlen($name)); 46*1729dd47SHenrik Yllemo $local .= pack('v', 0); 47*1729dd47SHenrik Yllemo $local .= $name; 48*1729dd47SHenrik Yllemo 49*1729dd47SHenrik Yllemo fwrite($fh, $local); 50*1729dd47SHenrik Yllemo fwrite($fh, $data); 51*1729dd47SHenrik Yllemo 52*1729dd47SHenrik Yllemo $central .= "PK\x01\x02"; 53*1729dd47SHenrik Yllemo $central .= pack('v', 20); // version made by 54*1729dd47SHenrik Yllemo $central .= pack('v', 20); // version needed 55*1729dd47SHenrik Yllemo $central .= pack('v', 0); 56*1729dd47SHenrik Yllemo $central .= pack('v', 0); 57*1729dd47SHenrik Yllemo $central .= pack('v', $time); 58*1729dd47SHenrik Yllemo $central .= pack('v', $date); 59*1729dd47SHenrik Yllemo $central .= pack('V', $crc); 60*1729dd47SHenrik Yllemo $central .= pack('V', $size); 61*1729dd47SHenrik Yllemo $central .= pack('V', $size); 62*1729dd47SHenrik Yllemo $central .= pack('v', strlen($name)); 63*1729dd47SHenrik Yllemo $central .= pack('v', 0); // extra length 64*1729dd47SHenrik Yllemo $central .= pack('v', 0); // comment length 65*1729dd47SHenrik Yllemo $central .= pack('v', 0); // disk start 66*1729dd47SHenrik Yllemo $central .= pack('v', 0); // internal attrs 67*1729dd47SHenrik Yllemo $central .= pack('V', 0); // external attrs 68*1729dd47SHenrik Yllemo $central .= pack('V', $offset); 69*1729dd47SHenrik Yllemo $central .= $name; 70*1729dd47SHenrik Yllemo 71*1729dd47SHenrik Yllemo $offset += strlen($local) + $size; 72*1729dd47SHenrik Yllemo } 73*1729dd47SHenrik Yllemo 74*1729dd47SHenrik Yllemo $centralOffset = $offset; 75*1729dd47SHenrik Yllemo fwrite($fh, $central); 76*1729dd47SHenrik Yllemo $centralSize = strlen($central); 77*1729dd47SHenrik Yllemo 78*1729dd47SHenrik Yllemo $end = "PK\x05\x06"; 79*1729dd47SHenrik Yllemo $end .= pack('v', 0); 80*1729dd47SHenrik Yllemo $end .= pack('v', 0); 81*1729dd47SHenrik Yllemo $end .= pack('v', count($this->entries)); 82*1729dd47SHenrik Yllemo $end .= pack('v', count($this->entries)); 83*1729dd47SHenrik Yllemo $end .= pack('V', $centralSize); 84*1729dd47SHenrik Yllemo $end .= pack('V', $centralOffset); 85*1729dd47SHenrik Yllemo $end .= pack('v', 0); 86*1729dd47SHenrik Yllemo fwrite($fh, $end); 87*1729dd47SHenrik Yllemo fclose($fh); 88*1729dd47SHenrik Yllemo return true; 89*1729dd47SHenrik Yllemo } 90*1729dd47SHenrik Yllemo 91*1729dd47SHenrik Yllemo private function dosDateTime() { 92*1729dd47SHenrik Yllemo $t = getdate(); 93*1729dd47SHenrik Yllemo $time = (($t['hours'] & 0x1f) << 11) | (($t['minutes'] & 0x3f) << 5) | (($t['seconds'] / 2) & 0x1f); 94*1729dd47SHenrik Yllemo $date = ((($t['year'] - 1980) & 0x7f) << 9) | (($t['mon'] & 0x0f) << 5) | ($t['mday'] & 0x1f); 95*1729dd47SHenrik Yllemo return array($time, $date); 96*1729dd47SHenrik Yllemo } 97*1729dd47SHenrik Yllemo} 98