#!/usr/bin/php -dphar.readonly=0
2,
'c' => 'text/plain',
'cc' => 'text/plain',
'cpp' => 'text/plain',
'c++' => 'text/plain',
'dtd' => 'text/plain',
'h' => 'text/plain',
'log' => 'text/plain',
'rng' => 'text/plain',
'txt' => 'text/plain',
'xsd' => 'text/plain',
'php' => 1,
'inc' => 1,
'avi' => 'video/avi',
'bmp' => 'image/bmp',
'css' => 'text/css',
'gif' => 'image/gif',
'htm' => 'text/html',
'html' => 'text/html',
'htmls' => 'text/html',
'ico' => 'image/x-ico',
'jpe' => 'image/jpeg',
'jpg' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'js' => 'application/x-javascript',
'midi' => 'audio/midi',
'mid' => 'audio/midi',
'mod' => 'audio/mod',
'mov' => 'movie/quicktime',
'mp3' => 'audio/mp3',
'mpg' => 'video/mpeg',
'mpeg' => 'video/mpeg',
'pdf' => 'application/pdf',
'png' => 'image/png',
'swf' => 'application/shockwave-flash',
'tif' => 'image/tiff',
'tiff' => 'image/tiff',
'wav' => 'audio/wav',
'xbm' => 'image/xbm',
'xml' => 'text/xml',
);
header("Cache-Control: no-cache, must-revalidate");
header("Pragma: no-cache");
$basename = basename(__FILE__);
if (!strpos($_SERVER['REQUEST_URI'], $basename)) {
chdir(Extract_Phar::$temp);
include $web;
return;
}
$pt = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], $basename) + strlen($basename));
if (!$pt || $pt == '/') {
$pt = $web;
header('HTTP/1.1 301 Moved Permanently');
header('Location: ' . $_SERVER['REQUEST_URI'] . '/' . $pt);
exit;
}
$a = realpath(Extract_Phar::$temp . DIRECTORY_SEPARATOR . $pt);
if (!$a || strlen(dirname($a)) < strlen(Extract_Phar::$temp)) {
header('HTTP/1.0 404 Not Found');
echo "\n
\n File Not Found\n \n \n 404 - File ", $pt, " Not Found
\n \n";
exit;
}
$b = pathinfo($a);
if (!isset($b['extension'])) {
header('Content-Type: text/plain');
header('Content-Length: ' . filesize($a));
readfile($a);
exit;
}
if (isset($mimes[$b['extension']])) {
if ($mimes[$b['extension']] === 1) {
include $a;
exit;
}
if ($mimes[$b['extension']] === 2) {
highlight_file($a);
exit;
}
header('Content-Type: ' .$mimes[$b['extension']]);
header('Content-Length: ' . filesize($a));
readfile($a);
exit;
}
}
class Extract_Phar
{
static $temp;
static $origdir;
const GZ = 0x1000;
const BZ2 = 0x2000;
const MASK = 0x3000;
const START = 'pharext_packager.php';
const LEN = 6696;
static function go($return = false)
{
$fp = fopen(__FILE__, 'rb');
fseek($fp, self::LEN);
$L = unpack('V', $a = (binary)fread($fp, 4));
$m = (binary)'';
do {
$read = 8192;
if ($L[1] - strlen($m) < 8192) {
$read = $L[1] - strlen($m);
}
$last = (binary)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 zlib-compressed .phars');
}
}
if ($f & self::BZ2) {
if (!function_exists('bzdecompress')) {
die('Error: bzip2 extension is not enabled -' .
' bzdecompress() function needed for bz2-compressed .phars');
}
}
$temp = self::tmpdir();
if (!$temp || !is_writable($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/'.basename(__FILE__, '.phar');
self::$temp = $temp;
self::$origdir = getcwd();
@mkdir($temp, 0777, true);
$temp = realpath($temp);
if (!file_exists($temp . DIRECTORY_SEPARATOR . md5_file(__FILE__))) {
self::_removeTmpFiles($temp, getcwd());
@mkdir($temp, 0777, true);
@file_put_contents($temp . '/' . md5_file(__FILE__), '');
foreach ($info['m'] as $path => $file) {
$a = !file_exists(dirname($temp . '/' . $path));
@mkdir(dirname($temp . '/' . $path), 0777, true);
clearstatcache();
if ($path[strlen($path) - 1] == '/') {
@mkdir($temp . '/' . $path, 0777);
} else {
file_put_contents($temp . '/' . $path, self::extractFile($path, $file, $fp));
@chmod($temp . '/' . $path, 0666);
}
}
}
chdir($temp);
if (!$return) {
include self::START;
}
}
static function tmpdir()
{
if (strpos(PHP_OS, 'WIN') !== false) {
if ($var = getenv('TMP') ? getenv('TMP') : getenv('TEMP')) {
return $var;
}
if (is_dir('/temp') || mkdir('/temp')) {
return realpath('/temp');
}
return false;
}
if ($var = getenv('TMPDIR')) {
return $var;
}
return realpath('/tmp');
}
static function _unpack($m)
{
$info = unpack('V', substr($m, 0, 4));
$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++) {
$len = unpack('V', substr($m, $start, 4));
$start += 4;
$savepath = substr($m, $start, $len[1]);
$start += $len[1];
$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("Invalid internal .phar file (size error " . strlen($data) . " != " .
$stat[7] . ")");
}
if ($entry[3] != sprintf("%u", crc32((binary)$data) & 0xffffffff)) {
die("Invalid internal .phar file (checksum error)");
}
return $data;
}
static function _removeTmpFiles($temp, $origdir)
{
chdir($temp);
foreach (glob('*') as $f) {
if (file_exists($f)) {
is_dir($f) ? @rmdir($f) : @unlink($f);
if (file_exists($f) && is_dir($f)) {
self::_removeTmpFiles($f, getcwd());
}
}
}
@rmdir($temp);
clearstatcache();
chdir($origdir);
}
}
Extract_Phar::go();
__HALT_COMPILER(); ?>
pharext.phar pharext/Cli/Args.php, QT, ˯a϶ pharext/Cli/Command.php QT Y pharext/Command.php; QT; pharext/Installer.php QT n =0 pharext/Openssl/PrivateKey.php QT 餝n pharext/Packager.php( QT( pharext/SourceDir/Git.phpR QTR pharext/SourceDir/Pecl.phpe QTe =~ pharext/SourceDir/Pharext.phpu QTu <ܶ pharext/SourceDir.php QT pharext/Version.php@ QT@ C뵶 pharext_install.tpl.php QT L pharext_installer.php QT pDZ pharext_packager.php QT 1 compile($spec);
}
/**
* Compile the original spec
* @param array $spec
* @return pharext\CliArgs self
*/
public function compile(array $spec = null) {
$this->orig = array_merge($this->orig, (array) $spec);
foreach ((array) $spec as $arg) {
if (isset($arg[0])) {
$this->spec["-".$arg[0]] = $arg;
}
$this->spec["--".$arg[1]] = $arg;
}
return $this;
}
/**
* Get original spec
* @return array
*/
public function getSpec() {
return $this->orig;
}
/**
* Get compiled spec
* @return array
*/
public function getCompiledSpec() {
return $this->spec;
}
/**
* Parse command line arguments according to the compiled spec.
*
* The Generator yields any parsing errors.
* Parsing will stop when all arguments are processed or the first option
* flagged CliArgs::HALT was encountered.
*
* @param int $argc
* @param array $argv
* @return Generator
*/
public function parse($argc, array $argv) {
for ($i = 0; $i < $argc; ++$i) {
$o = $argv[$i];
if ($o{0} === '-' && strlen($o) > 2 && $o{1} !== '-') {
// multiple short opts, .e.g -vps
$argc += strlen($o) - 2;
array_splice($argv, $i, 1, array_map(function($s) {
return "-$s";
}, str_split(substr($o, 1))));
$o = $argv[$i];
} elseif ($o{0} === '-' && strlen($o) > 2 && $o{1} === '-' && 0 < ($eq = strpos($o, "="))) {
$argc++;
array_splice($argv, $i, 1, [
substr($o, 0, $eq++),
substr($o, $eq)
]);
$o = $argv[$i];
}
if (!isset($this->spec[$o])) {
yield sprintf("Unknown option %s", $o);
} elseif (!$this->optAcceptsArg($o)) {
$this[$o] = true;
} elseif ($i+1 < $argc && !isset($this->spec[$argv[$i+1]])) {
$this[$o] = $argv[++$i];
} elseif ($this->optRequiresArg($o)) {
yield sprintf("Option --%s requires an argument", $this->optLongName($o));
} else {
// OPTARG
$this[$o] = $this->optDefaultArg($o);
}
if ($this->optHalts($o)) {
return;
}
}
}
/**
* Validate that all required options were given.
*
* The Generator yields any validation errors.
*
* @return Generator
*/
public function validate() {
$required = array_filter($this->orig, function($spec) {
return $spec[3] & self::REQUIRED;
});
foreach ($required as $req) {
if (!isset($this[$req[0]])) {
yield sprintf("Option --%s is required", $req[1]);
}
}
}
/**
* Retreive the default argument of an option
* @param string $o
* @return mixed
*/
private function optDefaultArg($o) {
$o = $this->opt($o);
if (isset($this->spec[$o][4])) {
return $this->spec[$o][4];
}
return null;
}
/**
* Retrieve the help message of an option
* @param string $o
* @return string
*/
private function optHelp($o) {
$o = $this->opt($o);
if (isset($this->spec[$o][2])) {
return $this->spec[$o][2];
}
return "";
}
/**
* Retrieve option's flags
* @param string $o
* @return int
*/
private function optFlags($o) {
$o = $this->opt($o);
if (isset($this->spec[$o])) {
return $this->spec[$o][3];
}
return null;
}
/**
* Check whether an option is flagged for halting argument processing
* @param string $o
* @return boolean
*/
private function optHalts($o) {
return $this->optFlags($o) & self::HALT;
}
/**
* Check whether an option needs an argument
* @param string $o
* @return boolean
*/
private function optRequiresArg($o) {
return $this->optFlags($o) & self::REQARG;
}
/**
* Check wether an option accepts any argument
* @param string $o
* @return boolean
*/
private function optAcceptsArg($o) {
return $this->optFlags($o) & 0xf00;
}
/**
* Check whether an option can be used more than once
* @param string $o
* @return boolean
*/
private function optIsMulti($o) {
return $this->optFlags($o) & self::MULTI;
}
/**
* Retreive the long name of an option
* @param string $o
* @return string
*/
private function optLongName($o) {
$o = $this->opt($o);
return $this->spec[$o][1];
}
/**
* Retreive the short name of an option
* @param string $o
* @return string
*/
private function optShortName($o) {
$o = $this->opt($o);
return $this->spec[$o][0];
}
/**
* Retreive the canonical name (--long-name) of an option
* @param string $o
* @return string
*/
private function opt($o) {
if ($o{0} !== '-') {
if (strlen($o) > 1) {
$o = "-$o";
}
$o = "-$o";
}
return $o;
}
/**@+
* Implements ArrayAccess and virtual properties
*/
function offsetExists($o) {
$o = $this->opt($o);
return isset($this->args[$o]);
}
function __isset($o) {
return $this->offsetExists($o);
}
function offsetGet($o) {
$o = $this->opt($o);
if (isset($this->args[$o])) {
return $this->args[$o];
}
return $this->optDefaultArg($o);
}
function __get($o) {
return $this->offsetGet($o);
}
function offsetSet($o, $v) {
$osn = $this->optShortName($o);
$oln = $this->optLongName($o);
if ($this->optIsMulti($o)) {
if (isset($osn)) {
$this->args["-$osn"][] = $v;
}
$this->args["--$oln"][] = $v;
} else {
if (isset($osn)) {
$this->args["-$osn"] = $v;
}
$this->args["--$oln"] = $v;
}
}
function __set($o, $v) {
$this->offsetSet($o, $v);
}
function offsetUnset($o) {
unset($this->args["-".$this->optShortName($o)]);
unset($this->args["--".$this->optLongName($o)]);
}
function __unset($o) {
$this->offsetUnset($o);
}
/**@-*/
}
args;
}
/**
* Output pharext vX.Y.Z header
*/
function header() {
printf("pharext v%s (c) Michael Wallner \n\n",
\pharext\VERSION);
}
/**
* @inheritdoc
* @see \pharext\Command::info()
*/
public function info($fmt) {
if (!$this->args->quiet) {
vprintf($fmt, array_slice(func_get_args(), 1));
}
}
/**
* @inheritdoc
* @see \pharext\Command::error()
*/
public function error($fmt) {
if (!$this->args->quiet) {
if (!isset($fmt)) {
$fmt = "%s\n";
$arg = error_get_last()["message"];
} else {
$arg = array_slice(func_get_args(), 1);
}
vfprintf(STDERR, "ERROR: $fmt", $arg);
}
}
/**
* Output command line help message
* @param string $prog
*/
public function help($prog) {
printf("Usage:\n\n \$ %s", $prog);
$flags = [];
$required = [];
$optional = [];
foreach ($this->args->getSpec() as $spec) {
if ($spec[3] & CliArgs::REQARG) {
if ($spec[3] & CliArgs::REQUIRED) {
$required[] = $spec;
} else {
$optional[] = $spec;
}
} else {
$flags[] = $spec;
}
}
if ($flags) {
printf(" [-%s]", implode("", array_column($flags, 0)));
}
foreach ($required as $req) {
printf(" -%s ", $req[0]);
}
if ($optional) {
printf(" [-%s ]", implode("|-", array_column($optional, 0)));
}
printf("\n\n");
$spc = $this->args->getSpec();
$max = max(array_map("strlen", array_column($spc, 1)));
$max += $max % 8 + 2;
foreach ($spc as $spec) {
if (isset($spec[0])) {
printf(" -%s|", $spec[0]);
} else {
printf(" ");
}
printf("--%s ", $spec[1]);
if ($spec[3] & CliArgs::REQARG) {
printf(" ");
} elseif ($spec[3] & CliArgs::OPTARG) {
printf("[]");
} else {
printf(" ");
}
printf("%s%s", str_repeat(" ", $max-strlen($spec[1])+3*!isset($spec[0])), $spec[2]);
if ($spec[3] & CliArgs::REQUIRED) {
printf(" (REQUIRED)");
}
if (isset($spec[4])) {
printf(" [%s]", $spec[4]);
}
printf("\n");
}
printf("\n");
}
/**
* Create temporary file/directory name
* @param string $prefix
* @param string $suffix
*/
private function tempname($prefix, $suffix = null) {
if (!isset($suffix)) {
$suffix = uniqid();
}
return sprintf("%s/%s.%s", sys_get_temp_dir(), $prefix, $suffix);
}
/**
* Create a new temp directory
* @param string $prefix
* @return string
*/
private function newtemp($prefix) {
$temp = $this->tempname($prefix);
if (!is_dir($temp)) {
if (!mkdir($temp, 0700, true)) {
$this->error(null);
exit(3);
}
}
return $temp;
}
/**
* rm -r
* @param string $dir
*/
private function rm($dir) {
foreach (scandir($dir) as $entry) {
if ($entry === "." || $entry === "..") {
continue;
} elseif (is_dir("$dir/$entry")) {
$this->rm("$dir/$entry");
} elseif (!unlink("$dir/$entry")) {
$this->error(null);
}
}
if (!rmdir($dir)) {
$this->error(null);
}
}
}
args = new CliArgs([
["h", "help", "Display help",
CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::NOARG|CliArgs::HALT],
["v", "verbose", "More output",
CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::NOARG],
["q", "quiet", "Less output",
CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::NOARG],
["p", "prefix", "PHP installation prefix if phpize is not in \$PATH, e.g. /opt/php7",
CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::REQARG],
["n", "common-name", "PHP common program name, e.g. php5 or zts-php",
CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::REQARG,
"php"],
["c", "configure", "Additional extension configure flags, e.g. -c --with-flag",
CliArgs::OPTIONAL|CliArgs::MULTI|CliArgs::REQARG],
["s", "sudo", "Installation might need increased privileges",
CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::OPTARG,
"sudo -S %s"]
]);
}
/**
* Cleanup temp directory
*/
public function __destruct() {
$this->cleanup();
}
/**
* @inheritdoc
* @see \pharext\Command::run()
*/
public function run($argc, array $argv) {
$this->cwd = getcwd();
$this->tmp = $this->tempname(basename(Phar::running(false)));
$phar = new Phar(Phar::running(false));
foreach ($phar as $entry) {
if (fnmatch("*.ext.phar*", $entry->getBaseName())) {
$temp = $this->newtemp($entry->getBaseName());
$phar->extractTo($temp, $entry->getFilename(), true);
$phars[$temp] = new Phar($temp."/".$entry->getFilename());
}
}
$phars[$this->tmp] = $phar;
foreach ($phars as $phar) {
if (isset($phar["pharext_install.php"])) {
$callable = include $phar["pharext_install.php"];
if (is_callable($callable)) {
$recv[] = $callable($this);
}
}
}
$errs = [];
$prog = array_shift($argv);
foreach ($this->args->parse(--$argc, $argv) as $error) {
$errs[] = $error;
}
if ($this->args["help"]) {
$this->header();
$this->help($prog);
exit;
}
foreach ($this->args->validate() as $error) {
$errs[] = $error;
}
if ($errs) {
if (!$this->args["quiet"]) {
$this->header();
}
foreach ($errs as $err) {
$this->error("%s\n", $err);
}
if (!$this->args["quiet"]) {
$this->help($prog);
}
exit(1);
}
if (isset($recv)) {
foreach ($recv as $r) {
$r($this);
}
}
foreach ($phars as $temp => $phar) {
$this->installPackage($phar, $temp);
}
}
/**
* Prepares, configures, builds and installs the extension
*/
private function installPackage(Phar $phar, $temp) {
$this->info("Installing %s ... \n", basename($phar->getAlias()));
try {
$phar->extractTo($temp, null, true);
} catch (\Exception $e) {
$this->error("%s\n", $e->getMessage());
exit(3);
}
if (!chdir($temp)) {
$this->error(null);
exit(4);
}
$this->exec("phpize", $this->php("ize"));
$this->exec("configure", "./configure --with-php-config=". $this->php("-config") . " ".
implode(" ", (array) $this->args->configure));
$this->exec("make", $this->args->verbose ? "make -j3" : "make -sj3");
$this->exec("install", $this->args->verbose ? "make install" : "make -s install", true);
$this->cleanup($temp);
$this->info("Don't forget to activiate the extension in your php.ini!\n\n");
}
/**
* Perform any cleanups
*/
private function cleanup($temp = null) {
if (!isset($temp)) {
$temp = $this->tmp;
}
if (is_dir($temp)) {
chdir($this->cwd);
$this->info("Cleaning up %s ...\n", $temp);
$this->rm($temp);
}
}
/**
* Execute a program with escalated privileges handling interactive password prompt
* @param string $command
* @param string $output
* @return int
*/
private function sudo($command, &$output) {
if (!($proc = proc_open($command, [STDIN,["pipe","w"],["pipe","w"]], $pipes))) {
return -1;
}
$stdout = $pipes[1];
$passwd = 0;
while (!feof($stdout)) {
$R = [$stdout]; $W = []; $E = [];
if (!stream_select($R, $W, $E, null)) {
continue;
}
$data = fread($stdout, 0x1000);
/* only check a few times */
if ($passwd++ < 10) {
if (stristr($data, "password")) {
printf("\n%s", $data);
}
}
$output .= $data;
}
return proc_close($proc);
}
/**
* Execute a system command
* @param string $name pretty name
* @param string $command full command
* @param bool $sudo whether the command may need escalated privileges
*/
private function exec($name, $command, $sudo = false) {
$this->info("Running %s ...%s", $this->args->verbose ? $command : $name, $this->args->verbose ? "\n" : " ");
if ($sudo && isset($this->args->sudo)) {
$retval = $this->sudo(sprintf($this->args->sudo." 2>&1", $command), $output);
} elseif ($this->args->verbose) {
passthru($command ." 2>&1", $retval);
} else {
exec($command ." 2>&1", $output, $retval);
$output = implode("\n", $output);
}
if ($retval) {
$this->error("Command %s failed with (%s)\n", $command, $retval);
if (isset($output) && !$this->args->quiet) {
printf("%s\n", $output);
}
exit(2);
}
$this->info("OK\n");
}
/**
* Construct a command from prefix common-name and suffix
* @param type $suffix
* @return string
*/
private function php($suffix) {
$cmd = $this->args["common-name"] . $suffix;
if (isset($this->args->prefix)) {
$cmd = $this->args->prefix . "/bin/" . $cmd;
}
return $cmd;
}
}
key = openssl_pkey_get_private("file://$file", $password);
if (!is_resource($this->key)) {
throw new \Exception("Could not load private key");
}
}
/**
* Sign the PHAR
* @param \Phar $package
*/
function sign(\Phar $package) {
$package->setSignatureAlgorithm(\Phar::OPENSSL, $this->key);
}
/**
* Export the public key to a file
* @param string $file
* @throws \Exception
*/
function exportPublicKey($file) {
if (!file_put_contents("$file.tmp", openssl_pkey_get_details($this->key)["key"])
|| !rename("$file.tmp", $file)
) {
throw new \Exception(error_get_last()["message"]);
}
}
}
args = new CliArgs([
["h", "help", "Display this help",
CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::NOARG|CliArgs::HALT],
["v", "verbose", "More output",
CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::NOARG],
["q", "quiet", "Less output",
CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::NOARG],
["n", "name", "Extension name",
CliArgs::REQUIRED|CliArgs::SINGLE|CliArgs::REQARG],
["r", "release", "Extension release version",
CliArgs::REQUIRED|CliArgs::SINGLE|CliArgs::REQARG],
["s", "source", "Extension source directory",
CliArgs::REQUIRED|CliArgs::SINGLE|CliArgs::REQARG],
["g", "git", "Use `git ls-tree` to determine file list",
CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::NOARG],
["p", "pecl", "Use PECL package.xml to determine file list, name and release",
CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::NOARG],
["d", "dest", "Destination directory",
CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::REQARG,
"."],
["z", "gzip", "Create additional PHAR compressed with gzip",
CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::NOARG],
["Z", "bzip", "Create additional PHAR compressed with bzip",
CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::NOARG],
["S", "sign", "Sign the PHAR with a private key",
CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::REQARG],
[null, "signature", "Dump signature",
CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::NOARG|CliArgs::HALT],
]);
}
/**
* @inheritdoc
* @see \pharext\Command::run()
*/
public function run($argc, array $argv) {
$errs = [];
$prog = array_shift($argv);
foreach ($this->args->parse(--$argc, $argv) as $error) {
$errs[] = $error;
}
if ($this->args["help"]) {
$this->header();
$this->help($prog);
exit;
}
if ($this->args["signature"]) {
exit($this->signature($prog));
}
try {
if ($this->args["source"]) {
if ($this->args["pecl"]) {
$this->source = new SourceDir\Pecl($this, $this->args["source"]);
} elseif ($this->args["git"]) {
$this->source = new SourceDir\Git($this, $this->args["source"]);
} else {
$this->source = new SourceDir\Pharext($this, $this->args["source"]);
}
}
} catch (\Exception $e) {
$errs[] = $e->getMessage();
}
foreach ($this->args->validate() as $error) {
$errs[] = $error;
}
if ($errs) {
if (!$this->args["quiet"]) {
$this->header();
}
foreach ($errs as $err) {
$this->error("%s\n", $err);
}
printf("\n");
if (!$this->args["quiet"]) {
$this->help($prog);
}
exit(1);
}
$this->createPackage();
}
function signature($prog) {
try {
$sig = (new Phar(Phar::running(false)))->getSignature();
printf("%s signature of %s\n%s", $sig["hash_type"], $prog,
chunk_split($sig["hash"], 64, "\n"));
return 0;
} catch (\Exception $e) {
$this->error("%s\n", $e->getMessage());
return 2;
}
}
/**
* Traverses all pharext source files to bundle
* @return Generator
*/
private function bundle() {
$rdi = new \RecursiveDirectoryIterator(__DIR__);
$rii = new \RecursiveIteratorIterator($rdi);
for ($rii->rewind(); $rii->valid(); $rii->next()) {
yield "pharext/". $rii->getSubPathname() => $rii->key();
}
}
private function askpass($prompt = "Password:") {
system("stty -echo", $retval);
if ($retval) {
$this->error("Could not disable echo on the terminal\n");
}
printf("%s ", $prompt);
$pass = fgets(STDIN, 1024);
system("stty echo");
if (substr($pass, -1) == "\n") {
$pass = substr($pass, 0, -1);
}
return $pass;
}
/**
* Creates the extension phar
*/
private function createPackage() {
$pkguniq = uniqid();
$pkgtemp = $this->tempname($pkguniq, "phar");
$pkgdesc = "{$this->args->name}-{$this->args->release}";
$this->info("Creating phar %s ...%s", $pkgtemp, $this->args->verbose ? "\n" : " ");
try {
$package = new Phar($pkgtemp);
if ($this->args->sign) {
$this->info("\nUsing private key to sign phar ... \n");
$privkey = new Openssl\PrivateKey(realpath($this->args->sign), $this->askpass());
$privkey->sign($package);
}
$package->startBuffering();
$package->buildFromIterator($this->source, $this->source->getBaseDir());
$package->buildFromIterator($this->bundle(__DIR__));
$package->addFile(__DIR__."/../pharext_installer.php", "pharext_installer.php");
$package->setDefaultStub("pharext_installer.php");
$package->setStub("#!/usr/bin/php -dphar.readonly=1\n".$package->getStub());
$package->stopBuffering();
if (!chmod($pkgtemp, 0777)) {
$this->error(null);
} elseif ($this->args->verbose) {
$this->info("Created executable phar %s\n", $pkgtemp);
} else {
$this->info("OK\n");
}
if ($this->args->gzip) {
$this->info("Compressing with gzip ... ");
try {
$package->compress(Phar::GZ)
->setDefaultStub("pharext_installer.php");
$this->info("OK\n");
} catch (\Exception $e) {
$this->error("%s\n", $e->getMessage());
}
}
if ($this->args->bzip) {
$this->info("Compressing with bzip ... ");
try {
$package->compress(Phar::BZ2)
->setDefaultStub("pharext_installer.php");
$this->info("OK\n");
} catch (\Exception $e) {
$this->error("%s\n", $e->getMessage());
}
}
unset($package);
} catch (\Exception $e) {
$this->error("%s\n", $e->getMessage());
exit(4);
}
foreach (glob($pkgtemp."*") as $pkgtemp) {
$pkgfile = str_replace($pkguniq, "{$pkgdesc}.ext", $pkgtemp);
$pkgname = $this->args->dest ."/". basename($pkgfile);
$this->info("Finalizing %s ... ", $pkgname);
if (!rename($pkgtemp, $pkgname)) {
$this->error(null);
exit(5);
}
$this->info("OK\n");
if ($this->args->sign && isset($privkey)) {
$keyname = $this->args->dest ."/". basename($pkgfile) . ".pubkey";
$this->info("Public Key %s ... ", $keyname);
try {
$privkey->exportPublicKey($keyname);
$this->info("OK\n");
} catch (\Exception $e) {
$this->error("%s", $e->getMessage());
}
}
}
}
}
cmd = $cmd;
$this->path = $path;
}
/**
* @inheritdoc
* @see \pharext\SourceDir::getBaseDir()
*/
public function getBaseDir() {
return $this->path;
}
/**
* Generate a list of files by `git ls-files`
* @return Generator
*/
private function generateFiles() {
$pwd = getcwd();
chdir($this->path);
if (($pipe = popen("git ls-tree -r --name-only HEAD", "r"))) {
while (!feof($pipe)) {
if (strlen($file = trim(fgets($pipe)))) {
if ($this->cmd->getArgs()->verbose) {
$this->cmd->info("Packaging %s\n", $file);
}
if (!($realpath = realpath($file))) {
$this->cmd->error("File %s does not exist\n", $file);
}
yield $realpath;
}
}
pclose($pipe);
}
chdir($pwd);
}
/**
* Implements IteratorAggregate
* @see IteratorAggregate::getIterator()
*/
public function getIterator() {
return $this->generateFiles();
}
}
registerXPathNamespace("pecl", $sxe->getDocNamespaces()[""]);
$args = $cmd->getArgs();
if (!isset($args->name)) {
$name = (string) $sxe->xpath("/pecl:package/pecl:name")[0];
foreach ($args->parse(2, ["--name", $name]) as $error) {
$cmd->error("%s\n", $error);
}
}
if (!isset($args->release)) {
$release = (string) $sxe->xpath("/pecl:package/pecl:version/pecl:release")[0];
foreach ($args->parse(2, ["--release", $release]) as $error) {
$cmd->error("%s\n", $error);
}
}
$this->cmd = $cmd;
$this->sxe = $sxe;
$this->path = $path;
}
/**
* @inheritdoc
* @see \pharext\SourceDir::getBaseDir()
*/
public function getBaseDir() {
return $this->path;
}
/**
* Compute the path of a file by parent dir nodes
* @param \SimpleXMLElement $ele
* @return string
*/
private function dirOf($ele) {
$path = "";
while (($ele = current($ele->xpath(".."))) && $ele->getName() == "dir") {
$path = trim($ele["name"], "/") ."/". $path ;
}
return trim($path, "/");
}
/**
* Render installer hook
* @param array $configure
* @return string
*/
private static function loadHook($configure, $dependencies) {
return include __DIR__."/../pharext_install.tpl.php";
}
/**
* Create installer hook
* @return \Generator
*/
private function generateHooks() {
$dependencies = $this->sxe->xpath("/pecl:package/pecl:dependencies/pecl:required/pecl:package");
foreach ($dependencies as $key => $dep) {
if (($glob = glob("{$this->path}/{$dep->name}-*.ext.phar*"))) {
usort($glob, function($a, $b) {
return version_compare(
substr($a, strpos(".ext.phar", $a)),
substr($b, strpos(".ext.phar", $b))
);
});
yield realpath($this->path."/".end($glob));
} else {
unset($dependencies[$key]);
}
}
$configure = $this->sxe->xpath("/pecl:package/pecl:extsrcrelease/pecl:configureoption");
if ($configure) {
$fd = tmpfile();
ob_start(function($s) use($fd){
fwrite($fd, $s);
return null;
});
self::loadHook($configure, $dependencies);
ob_end_flush();
rewind($fd);
yield "pharext_install.php" => $fd;
}
}
/**
* Generate a list of files from the package.xml
* @return Generator
*/
private function generateFiles() {
foreach ($this->generateHooks() as $file => $hook) {
if ($this->cmd->getArgs()->verbose) {
$this->cmd->info("Packaging %s\n", is_string($hook) ? $hook : $file);
}
yield $file => $hook;
}
foreach ($this->sxe->xpath("//pecl:file") as $file) {
$path = $this->path ."/". $this->dirOf($file) ."/". $file["name"];
if ($this->cmd->getArgs()->verbose) {
$this->cmd->info("Packaging %s\n", $path);
}
if (!($realpath = realpath($path))) {
$this->cmd->error("File %s does not exist", $path);
}
yield $realpath;
}
}
/**
* Implements IteratorAggregate
* @see IteratorAggregate::getIterator()
*/
public function getIterator() {
return $this->generateFiles();
}
}
cmd = $cmd;
$this->path = $path;
$callable = include "$path/pharext_package.php";
if (!is_callable($callable)) {
throw new \Exception("Package hook did not return a callable");
}
$this->iter = $callable($cmd, $path);
}
/**
* @inheritdoc
* @see \pharext\SourceDir::getBaseDir()
*/
public function getBaseDir() {
return $this->path;
}
/**
* Implements IteratorAggregate
* @see IteratorAggregate::getIterator()
*/
public function getIterator() {
if (!is_callable($this->iter)) {
return new Git($this->cmd, $this->path);
}
return call_user_func($this->iter, $this->cmd, $this->path);
}
}
/**
* Generated by pharext v=pharext\VERSION?> at =date("Y-m-d H:i:i T")?>.
*/
namespace pharext;
use pharext\Cli\Args as CliArgs;
return function(Installer $installer) {
$args = $installer->getArgs();
$args->compile([[
null,
"=$cfg["name"]?>",
"=ucfirst($cfg["prompt"])?>",
CliArgs::OPTARG,
"=$cfg["default"]?>"
NULL
]]);
return function(Installer $installer) {
$args = $installer->getArgs();
if (isset($args["=$cfg["name"]?>"])) {
$args->configure = "--=$cfg["name"]?>=".$args["=$cfg["name"]?>"];
}
};
};
run($argc, $argv);
run($argc, $argv);
N5g
,-9 GBMB