Passed
Pull Request — master (#39)
by Théo
02:13
created

Extract_Phar::tmpdir()   B

Complexity

Conditions 7
Paths 5

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 15
rs 8.2222
c 0
b 0
f 0
cc 7
eloc 9
nc 5
nop 0
1
<?php
2
3
$web = 'index.php';
4
5
if (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
13
if (@(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 ", $pt, " 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
103
class 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 = 6653;
112
113
    static function go($return = false)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
114
    {
115
        $fp = fopen(__FILE__, 'rb');
116
        fseek($fp, self::LEN);
0 ignored issues
show
Bug introduced by
It seems like $fp can also be of type false; however, parameter $handle of fseek() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

116
        fseek(/** @scrutinizer ignore-type */ $fp, self::LEN);
Loading history...
117
        $L = unpack('V', $a = fread($fp, 4));
0 ignored issues
show
Bug introduced by
It seems like $fp can also be of type false; however, parameter $handle of fread() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

117
        $L = unpack('V', $a = fread(/** @scrutinizer ignore-type */ $fp, 4));
Loading history...
118
        $m = '';
119
120
        do {
121
            $read = 8192;
122
            if ($L[1] - strlen($m) < 8192) {
123
                $read = $L[1] - strlen($m);
124
            }
125
            $last = 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 "' .
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
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 -' .
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
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 -' .
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
148
                    ' bzdecompress() function needed for bz2-compressed .phars');
149
            }
150
        }
151
152
        $temp = self::tmpdir();
153
154
        if (!$temp || !is_writable($temp)) {
0 ignored issues
show
Bug introduced by
It seems like $temp can also be of type array; however, parameter $filename of is_writable() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

154
        if (!$temp || !is_writable(/** @scrutinizer ignore-type */ $temp)) {
Loading history...
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');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
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);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for mkdir(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

167
        /** @scrutinizer ignore-unhandled */ @mkdir($temp, 0777, true);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
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__), '');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for file_put_contents(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

173
            /** @scrutinizer ignore-unhandled */ @file_put_contents($temp . '/' . md5_file(__FILE__), '');

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
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);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for chmod(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

184
                    /** @scrutinizer ignore-unhandled */ @chmod($temp . '/' . $path, 0666);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
185
                }
186
            }
187
        }
188
189
        chdir($temp);
190
191
        if (!$return) {
192
            include self::START;
193
        }
194
    }
195
196
    static function tmpdir()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
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)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
214
    {
215
        $info = unpack('V', substr($m, 0, 4));
216
        $l = unpack('V', substr($m, 10, 4));
217
        $m = substr($m, 14 + $l[1]);
218
        $s = unpack('V', substr($m, 0, 4));
219
        $o = 0;
220
        $start = 4 + $s[1];
221
        $ret['c'] = 0;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$ret was never initialized. Although not strictly required by PHP, it is generally a good practice to add $ret = array(); before regardless.
Loading history...
222
223
        for ($i = 0; $i < $info[1]; $i++) {
224
            $len = unpack('V', substr($m, $start, 4));
225
            $start += 4;
226
            $savepath = substr($m, $start, $len[1]);
227
            $start += $len[1];
228
            $ret['m'][$savepath] = array_values(unpack('Va/Vb/Vc/Vd/Ve/Vf', substr($m, $start, 24)));
229
            $ret['m'][$savepath][3] = sprintf('%u', $ret['m'][$savepath][3]
230
                & 0xffffffff);
231
            $ret['m'][$savepath][7] = $o;
232
            $o += $ret['m'][$savepath][2];
233
            $start += 24 + $ret['m'][$savepath][5];
234
            $ret['c'] |= $ret['m'][$savepath][4] & self::MASK;
235
        }
236
        return $ret;
237
    }
238
239
    static function extractFile($path, $entry, $fp)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Unused Code introduced by
The parameter $path is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

239
    static function extractFile(/** @scrutinizer ignore-unused */ $path, $entry, $fp)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
240
    {
241
        $data = '';
242
        $c = $entry[2];
243
244
        while ($c) {
245
            if ($c < 8192) {
246
                $data .= @fread($fp, $c);
247
                $c = 0;
248
            } else {
249
                $c -= 8192;
250
                $data .= @fread($fp, 8192);
251
            }
252
        }
253
254
        if ($entry[4] & self::GZ) {
255
            $data = gzinflate($data);
256
        } elseif ($entry[4] & self::BZ2) {
257
            $data = bzdecompress($data);
258
        }
259
260
        if (strlen($data) != $entry[0]) {
261
            die("Invalid internal .phar file (size error " . strlen($data) . " != " .
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
262
                $stat[7] . ")");
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $stat seems to be never defined.
Loading history...
263
        }
264
265
        if ($entry[3] != sprintf("%u", crc32($data) & 0xffffffff)) {
266
            die("Invalid internal .phar file (checksum error)");
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
267
        }
268
269
        return $data;
270
    }
271
272
    static function _removeTmpFiles($temp, $origdir)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
273
    {
274
        chdir($temp);
275
276
        foreach (glob('*') as $f) {
277
            if (file_exists($f)) {
278
                is_dir($f) ? @rmdir($f) : @unlink($f);
279
                if (file_exists($f) && is_dir($f)) {
280
                    self::_removeTmpFiles($f, getcwd());
281
                }
282
            }
283
        }
284
285
        @rmdir($temp);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for rmdir(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

285
        /** @scrutinizer ignore-unhandled */ @rmdir($temp);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
286
        clearstatcache();
287
        chdir($origdir);
288
    }
289
}
290
291
Extract_Phar::go();
292
__HALT_COMPILER(); ?>
293