xref: /php-src/ext/phar/shortarc.php (revision ba0913a2)
1<?php
2
3$web = '000';
4
5if (in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) {
6    Phar::interceptFileFuncs();
7    set_include_path('phar://' . __FILE__ . PATH_SEPARATOR . get_include_path());
8    Phar::webPhar(null, $web);
9    include 'phar://' . __FILE__ . '/' . Extract_Phar::START;
10    return;
11}
12
13if (@(isset($_SERVER['REQUEST_URI']) && isset($_SERVER['REQUEST_METHOD']) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'POST'))) {
14    Extract_Phar::go(true);
15    $mimes = array(
16        'phps' => 2,
17        'c' => 'text/plain',
18        'cc' => 'text/plain',
19        'cpp' => 'text/plain',
20        'c++' => 'text/plain',
21        'dtd' => 'text/plain',
22        'h' => 'text/plain',
23        'log' => 'text/plain',
24        'rng' => 'text/plain',
25        'txt' => 'text/plain',
26        'xsd' => 'text/plain',
27        'php' => 1,
28        'inc' => 1,
29        'avi' => 'video/avi',
30        'bmp' => 'image/bmp',
31        'css' => 'text/css',
32        'gif' => 'image/gif',
33        'htm' => 'text/html',
34        'html' => 'text/html',
35        'htmls' => 'text/html',
36        'ico' => 'image/x-ico',
37        'jpe' => 'image/jpeg',
38        'jpg' => 'image/jpeg',
39        'jpeg' => 'image/jpeg',
40        'js' => 'application/x-javascript',
41        'midi' => 'audio/midi',
42        'mid' => 'audio/midi',
43        'mod' => 'audio/mod',
44        'mov' => 'movie/quicktime',
45        'mp3' => 'audio/mp3',
46        'mpg' => 'video/mpeg',
47        'mpeg' => 'video/mpeg',
48        'pdf' => 'application/pdf',
49        'png' => 'image/png',
50        'swf' => 'application/shockwave-flash',
51        'tif' => 'image/tiff',
52        'tiff' => 'image/tiff',
53        'wav' => 'audio/wav',
54        'xbm' => 'image/xbm',
55        'xml' => 'text/xml',
56       );
57
58    header("Cache-Control: no-cache, must-revalidate");
59    header("Pragma: no-cache");
60
61    $basename = basename(__FILE__);
62    if (!strpos($_SERVER['REQUEST_URI'], $basename)) {
63        chdir(Extract_Phar::$temp);
64        include $web;
65        return;
66    }
67    $pt = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], $basename) + strlen($basename));
68    if (!$pt || $pt == '/') {
69        $pt = $web;
70        header('HTTP/1.1 301 Moved Permanently');
71        header('Location: ' . $_SERVER['REQUEST_URI'] . '/' . $pt);
72        exit;
73    }
74    $a = realpath(Extract_Phar::$temp . DIRECTORY_SEPARATOR . $pt);
75    if (!$a || strlen(dirname($a)) < strlen(Extract_Phar::$temp)) {
76        header('HTTP/1.0 404 Not Found');
77        echo "<html>\n <head>\n  <title>File Not Found<title>\n </head>\n <body>\n  <h1>404 - File Not Found</h1>\n </body>\n</html>";
78        exit;
79    }
80    $b = pathinfo($a);
81    if (!isset($b['extension'])) {
82        header('Content-Type: text/plain');
83        header('Content-Length: ' . filesize($a));
84        readfile($a);
85        exit;
86    }
87    if (isset($mimes[$b['extension']])) {
88        if ($mimes[$b['extension']] === 1) {
89            include $a;
90            exit;
91        }
92        if ($mimes[$b['extension']] === 2) {
93            highlight_file($a);
94            exit;
95        }
96        header('Content-Type: ' .$mimes[$b['extension']]);
97        header('Content-Length: ' . filesize($a));
98        readfile($a);
99        exit;
100    }
101}
102
103class Extract_Phar
104{
105    static $temp;
106    static $origdir;
107    const GZ = 0x1000;
108    const BZ2 = 0x2000;
109    const MASK = 0x3000;
110    const START = 'index.php';
111    const LEN = XXXX;
112
113    static function go($return  = false)
114    {
115        $fp = fopen(__FILE__, 'rb');
116        fseek($fp, self::LEN);
117        $L = unpack('V', $a = (binary)fread($fp, 4));
118        $m = (binary)'';
119
120        do {
121            $read = 8192;
122            if ($L[1] - strlen($m) < 8192) {
123                $read = $L[1] - strlen($m);
124            }
125            $last = (binary)fread($fp, $read);
126            $m .= $last;
127        } while (strlen($last) && strlen($m) < $L[1]);
128
129        if (strlen($m) < $L[1]) {
130            die('ERROR: manifest length read was "' .
131                strlen($m) .'" should be "' .
132                $L[1] . '"');
133        }
134
135        $info = self::_unpack($m);
136        $f = $info['c'];
137
138        if ($f & self::GZ) {
139            if (!function_exists('gzinflate')) {
140                die('Error: zlib extension is not enabled -' .
141                    ' gzinflate() function needed for zlib-compressed .phars');
142            }
143        }
144
145        if ($f & self::BZ2) {
146            if (!function_exists('bzdecompress')) {
147                die('Error: bzip2 extension is not enabled -' .
148                    ' bzdecompress() function needed for bz2-compressed .phars');
149            }
150        }
151
152        $temp = self::tmpdir();
153
154        if (!$temp || !is_writable($temp)) {
155            $sessionpath = session_save_path();
156            if (strpos ($sessionpath, ";") !== false)
157                $sessionpath = substr ($sessionpath, strpos ($sessionpath, ";")+1);
158            if (!file_exists($sessionpath) || !is_dir($sessionpath)) {
159                die('Could not locate temporary directory to extract phar');
160            }
161            $temp = $sessionpath;
162        }
163
164        $temp .= '/pharextract/'.basename(__FILE__, '.phar');
165        self::$temp = $temp;
166        self::$origdir = getcwd();
167        @mkdir($temp, 0777, true);
168        $temp = realpath($temp);
169
170        if (!file_exists($temp . DIRECTORY_SEPARATOR . md5_file(__FILE__))) {
171            self::_removeTmpFiles($temp, getcwd());
172            @mkdir($temp, 0777, true);
173            @file_put_contents($temp . '/' . md5_file(__FILE__), '');
174
175            foreach ($info['m'] as $path => $file) {
176                $a = !file_exists(dirname($temp . '/' . $path));
177                @mkdir(dirname($temp . '/' . $path), 0777, true);
178                clearstatcache();
179
180                if ($path[strlen($path) - 1] == '/') {
181                    @mkdir($temp . '/' . $path, 0777);
182                } else {
183                    file_put_contents($temp . '/' . $path, self::extractFile($path, $file, $fp));
184                    @chmod($temp . '/' . $path, 0666);
185                }
186            }
187        }
188
189        chdir($temp);
190
191        if (!$return) {
192            include self::START;
193        }
194    }
195
196    static function tmpdir()
197    {
198        if (strpos(PHP_OS, 'WIN') !== false) {
199            if ($var = getenv('TMP') ? getenv('TMP') : getenv('TEMP')) {
200                return $var;
201            }
202            if (is_dir('/temp') || mkdir('/temp')) {
203                return realpath('/temp');
204            }
205            return false;
206        }
207        if ($var = getenv('TMPDIR')) {
208            return $var;
209        }
210        return realpath('/tmp');
211    }
212
213    static function _unpack($m)
214    {
215        $info = unpack('V', substr($m, 0, 4));
216        // skip API version, phar flags, alias, metadata
217        $l = unpack('V', substr($m, 10, 4));
218        $m = substr($m, 14 + $l[1]);
219        $s = unpack('V', substr($m, 0, 4));
220        $o = 0;
221        $start = 4 + $s[1];
222        $ret['c'] = 0;
223
224        for ($i = 0; $i < $info[1]; $i++) {
225            // length of the file name
226            $len = unpack('V', substr($m, $start, 4));
227            $start += 4;
228            // file name
229            $savepath = substr($m, $start, $len[1]);
230            $start += $len[1];
231            // retrieve manifest data:
232            // 0 = size, 1 = timestamp, 2 = compressed size, 3 = crc32, 4 = flags
233            // 5 = metadata length
234            $ret['m'][$savepath] = array_values(unpack('Va/Vb/Vc/Vd/Ve/Vf', substr($m, $start, 24)));
235            $ret['m'][$savepath][3] = sprintf('%u', $ret['m'][$savepath][3]
236                & 0xffffffff);
237            $ret['m'][$savepath][7] = $o;
238            $o += $ret['m'][$savepath][2];
239            $start += 24 + $ret['m'][$savepath][5];
240            $ret['c'] |= $ret['m'][$savepath][4] & self::MASK;
241        }
242        return $ret;
243    }
244
245    static function extractFile($path, $entry, $fp)
246    {
247        $data = '';
248        $c = $entry[2];
249
250        while ($c) {
251            if ($c < 8192) {
252                $data .= @fread($fp, $c);
253                $c = 0;
254            } else {
255                $c -= 8192;
256                $data .= @fread($fp, 8192);
257            }
258        }
259
260        if ($entry[4] & self::GZ) {
261            $data = gzinflate($data);
262        } elseif ($entry[4] & self::BZ2) {
263            $data = bzdecompress($data);
264        }
265
266        if (strlen($data) != $entry[0]) {
267            die("Invalid internal .phar file (size error " . strlen($data) . " != " .
268                $entry[0] . ")");
269        }
270
271        if ($entry[3] != sprintf("%u", crc32((binary)$data) & 0xffffffff)) {
272            die("Invalid internal .phar file (checksum error)");
273        }
274
275        return $data;
276    }
277
278    static function _removeTmpFiles($temp, $origdir)
279    {
280        chdir($temp);
281
282        foreach (glob('*') as $f) {
283            if (file_exists($f)) {
284                is_dir($f) ? @rmdir($f) : @unlink($f);
285                if (file_exists($f) && is_dir($f)) {
286                    self::_removeTmpFiles($f, getcwd());
287                }
288            }
289        }
290
291        @rmdir($temp);
292        clearstatcache();
293        chdir($origdir);
294    }
295}
296