mirror of
https://github.com/php/php-src.git
synced 2025-01-14 15:54:36 +08:00
7540adf058
the new default stub allows creation of phars that run identically 1) with Phar extension 2) without Phar extension 3) extracted to disk from the phar this makes the default phar format quite interesting as it eliminates the only drawback of the extension
176 lines
5.9 KiB
PHP
176 lines
5.9 KiB
PHP
<?php
|
|
if (in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) {
|
|
Phar::interceptFileFuncs();
|
|
include 'phar://' . __FILE__ . '/index.php';
|
|
return;
|
|
}
|
|
class Extract_Phar
|
|
{
|
|
static $tmp = array();
|
|
static $origdir;
|
|
const GZ = 0x1000;
|
|
const BZ2 = 0x2000;
|
|
const MASK = 0x3000;
|
|
static function go($D)
|
|
{
|
|
register_shutdown_function(array('Extract_Phar', '_removeTmpFiles'));
|
|
$fp = fopen(__FILE__, 'rb');
|
|
fseek($fp, $D);
|
|
$L = unpack('V', fread($fp, 4));
|
|
$m = '';
|
|
do {
|
|
$read = 8192;
|
|
if ($L[1] - strlen($m) < 8192) {
|
|
$read = $L[1] - strlen($m);
|
|
}
|
|
$last = fread($fp, $read);
|
|
$m .= $last;
|
|
} while (strlen($last) && strlen($m) < $L[1]);
|
|
if (strlen($m) < $L[1]) {
|
|
die('ERROR: manifest length read was "' .
|
|
strlen($m) .'" should be "' .
|
|
$L[1] . '"');
|
|
}
|
|
$info = self::_unpack($m);
|
|
$f = $info['c'];
|
|
if ($f & self::GZ) {
|
|
if (!function_exists('gzinflate')) {
|
|
die('Error: zlib extension is not enabled - gzinflate() function needed' .
|
|
' for compressed .phars');
|
|
}
|
|
}
|
|
if ($f & self::BZ2) {
|
|
if (!function_exists('bzdecompress')) {
|
|
die('Error: bzip2 extension is not enabled - bzdecompress() function needed' .
|
|
' for compressed .phars');
|
|
}
|
|
}
|
|
$temp = self::tmpdir();
|
|
if (!$temp) {
|
|
$sessionpath = session_save_path();
|
|
if (strpos ($sessionpath, ";") !== FALSE)
|
|
$sessionpath = substr ($sessionpath, strpos ($sessionpath, ";")+1);
|
|
if (!file_exists($sessionpath) && !is_dir($sessionpath)) {
|
|
die('Could not locate temporary directory to extract phar');
|
|
}
|
|
$temp = $sessionpath;
|
|
}
|
|
$temp .= '/pharextract';
|
|
if (!file_exists($temp)) {
|
|
@mkdir($temp);
|
|
$temp = realpath($temp);
|
|
self::$tmp[] = $temp;
|
|
}
|
|
self::$origdir = getcwd();
|
|
foreach ($info['m'] as $path => $file) {
|
|
$a = !file_exists(dirname($temp . '/' . $path));
|
|
@mkdir(dirname($temp . '/' . $path), 0777, true);
|
|
clearstatcache();
|
|
if ($a) self::$tmp[] = realpath(dirname($temp . '/' . $path));
|
|
if ($path[strlen($path) - 1] == '/') {
|
|
mkdir($temp . '/' . $path);
|
|
} else {
|
|
file_put_contents($temp . '/' . $path, self::extractFile($path, $file, $fp));
|
|
}
|
|
self::$tmp[] = realpath($temp . '/' . $path);
|
|
}
|
|
chdir($temp);
|
|
include 'index.php';
|
|
}
|
|
|
|
static function tmpdir()
|
|
{
|
|
if (strpos(PHP_OS, 'WIN') !== false) {
|
|
if ($var = isset($_ENV['TMP']) ? $_ENV['TMP'] : getenv('TMP')) {
|
|
return $var;
|
|
}
|
|
if ($var = isset($_ENV['TEMP']) ? $_ENV['TEMP'] : getenv('TEMP')) {
|
|
return $var;
|
|
}
|
|
if ($var = isset($_ENV['USERPROFILE']) ? $_ENV['USERPROFILE'] : @getenv('USERPROFILE')) {
|
|
return $var;
|
|
}
|
|
if ($var = isset($_ENV['windir']) ? $_ENV['windir'] : getenv('windir')) {
|
|
return $var;
|
|
}
|
|
return @getenv('SystemRoot') . '\temp';
|
|
}
|
|
if ($var = isset($_ENV['TMPDIR']) ? $_ENV['TMPDIR'] : getenv('TMPDIR')) {
|
|
return $var;
|
|
}
|
|
return realpath('/tmp');
|
|
}
|
|
|
|
static function _unpack($m)
|
|
{
|
|
$info = unpack('V', substr($m, 0, 4));
|
|
// skip API version, phar flags, alias, metadata
|
|
$l = unpack('V', substr($m, 10, 4));
|
|
$m = substr($m, 14 + $l[1]);
|
|
$s = unpack('V', substr($m, 0, 4));
|
|
$o = 0;
|
|
$start = 4 + $s[1];
|
|
$ret['c'] = 0;
|
|
for ($i = 0; $i < $info[1]; $i++) {
|
|
// length of the file name
|
|
$len = unpack('V', substr($m, $start, 4));
|
|
$start += 4;
|
|
// file name
|
|
$savepath = substr($m, $start, $len[1]);
|
|
$start += $len[1];
|
|
// retrieve manifest data:
|
|
// 0 = size, 1 = timestamp, 2 = compressed size, 3 = crc32, 4 = flags
|
|
// 5 = metadata length
|
|
$ret['m'][$savepath] = array_values(unpack('Va/Vb/Vc/Vd/Ve/Vf', substr($m, $start, 24)));
|
|
$ret['m'][$savepath][3] = sprintf('%u', $ret['m'][$savepath][3]
|
|
& 0xffffffff);
|
|
$ret['m'][$savepath][7] = $o;
|
|
$o += $ret['m'][$savepath][2];
|
|
$start += 24 + $ret['m'][$savepath][5];
|
|
$ret['c'] |= $ret['m'][$savepath][4] & self::MASK;
|
|
}
|
|
return $ret;
|
|
}
|
|
|
|
static function extractFile($path, $entry, $fp)
|
|
{
|
|
$data = '';
|
|
$c = $entry[2];
|
|
while ($c) {
|
|
if ($c < 8192) {
|
|
$data .= @fread($fp, $c);
|
|
$c = 0;
|
|
} else {
|
|
$c -= 8192;
|
|
$data .= @fread($fp, 8192);
|
|
}
|
|
}
|
|
if ($entry[4] & self::GZ) {
|
|
$data = gzinflate($data);
|
|
} elseif ($entry[4] & self::BZ2) {
|
|
$data = bzdecompress($data);
|
|
}
|
|
if (strlen($data) != $entry[0]) {
|
|
die("Not valid internal .phar file (size error " . strlen($data) . " != " .
|
|
$stat[7] . ")");
|
|
}
|
|
if ($entry[3] != sprintf("%u", crc32($data) & 0xffffffff)) {
|
|
die("Not valid internal .phar file (checksum error)");
|
|
}
|
|
return $data;
|
|
}
|
|
|
|
static function _removeTmpFiles()
|
|
{
|
|
// for removal of temp files
|
|
usort(self::$tmp, 'strnatcasecmp');
|
|
array_reverse(self::$tmp, 1);
|
|
if (count(self::$tmp)) {
|
|
foreach (self::$tmp as $f) {
|
|
if (file_exists($f)) is_dir($f) ? @rmdir($f) : @unlink($f);
|
|
}
|
|
|
|
}
|
|
chdir(self::$origdir);
|
|
}
|
|
} |