xref: /plugin/skillforge/classes/StoredZipWriter.php (revision 1729dd472fd5524951126802d13bd2e76b84b680)
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