codekingpro/portable-devtools
116k
1<?php2 3/** @file phar.php4 * @ingroup Phar5 * @brief class CLICommand6 * @author Marcus Boerger7 * @date 2007 - 20088 *9 * Phar Command10 */11 12if (!extension_loaded('phar'))13{14 if (!class_exists('PHP_Archive', 0)) {15 echo "Neither Extension Phar nor class PHP_Archive are available.\n";16 exit(1);17 }18 if (!in_array('phar', stream_get_wrappers())) {19 stream_wrapper_register('phar', 'PHP_Archive');20 }21 if (!class_exists('Phar',0)) {22 require 'phar://'.__FILE__.'/phar.inc';23 }24}25 26foreach(array("SPL", "Reflection") as $ext)27{28 if (!extension_loaded($ext)) {29 echo "$argv[0] requires PHP extension $ext.\n";30 exit(1);31 }32}33 34function command_include($file)35{36 $file = 'phar://' . __FILE__ . '/' . $file;37 if (file_exists($file)) {38 include($file);39 }40}41 42function command_autoload($classname)43{44 command_include(strtolower($classname) . '.inc');45}46 47Phar::mapPhar();48 49spl_autoload_register('command_autoload');50 51new PharCommand($argc, $argv);52 53__HALT_COMPILER(); ?>
546 pharcommand clicommand.inc�* ��i�* �"�۶ directorygraphiterator.incD ��iD �*=D� directorytreeiterator.inc� ��i� ���� invertedregexiterator.inc� ��i� �Xf�� phar.inc� ��i� �;1H� pharcommand.inc� ��i� ��b� <?php55 56/** @file clicommand.inc57 * @ingroup Phar58 * @brief class CLICommand59 * @author Marcus Boerger60 * @date 2007 - 200861 *62 * Phar Command63 */64 65/** @ingroup Phar66 * @brief Abstract base console command implementation67 * @author Marcus Boerger68 * @version 1.069 */70abstract class CLICommand71{72 protected $argc;73 protected $argv;74 protected $cmds = array();75 protected $args = array();76 protected $typs = array();77 78 function __construct($argc, array $argv)79 {80 $this->argc = $argc;81 $this->argv = $argv;82 $this->cmds = self::getCommands($this);83 $this->typs = self::getArgTyps($this);84 85 if ($argc < 2) {86 self::error("No command given, check {$argv[0]} help\n");87 } elseif (!isset($this->cmds[$argv[1]]['run'])) {88 self::error("Unknown command '{$argv[1]}', check {$argv[0]} help\n");89 } else {90 $command = $argv[1];91 }92 93 if (isset($this->cmds[$command]['arg'])) {94 $this->args = call_user_func(array($this, $this->cmds[$command]['arg']));95 $i = 1;96 $missing = false;97 while (++$i < $argc) {98 if ($argv[$i][0] == '-') {99 if (strlen($argv[$i]) == 2 && isset($this->args[$argv[$i][1]])) {100 $arg = $argv[$i][1];101 if (++$i >= $argc) {102 self::error("Missing argument to parameter '$arg' of command '$command', check {$argv[0]} help\n");103 } else {104 $this->args[$arg]['val'] = $this->checkArgTyp($arg, $i, $argc, $argv);105 }106 } else {107 self::error("Unknown parameter '{$argv[$i]}' to command $command, check {$argv[0]} help\n");108 }109 } else {110 break;111 }112 }113 114 if (isset($this->args[''])) {115 if ($i >= $argc) {116 if (isset($this->args['']['require']) && $this->args['']['require']) {117 self::error("Missing default trailing arguments to command $command, check {$argv[0]} help\n");118 }119 } else {120 $this->args['']['val'] = array();121 while($i < $argc) {122 $this->args['']['val'][] = $argv[$i++];123 }124 }125 } else if ($i < $argc) {126 self::error("Unexpected default arguments to command $command, check {$argv[0]} help\n");127 }128 129 foreach($this->args as $arg => $inf) {130 if (strlen($arg) && !isset($inf['val']) && isset($inf['required']) && $inf['required']) {131 $missing .= "Missing parameter '-$arg' to command $command, check {$argv[0]} help\n";132 }133 }134 135 if (strlen($missing)) {136 self::error($missing);137 }138 }139 140 call_user_func(array($this, $this->cmds[$command]['run']), $this->args);141 }142 143 static function notice ($msg)144 {145 fprintf(STDERR, $msg);146 }147 148 static function error ($msg, $exit_code = 1)149 {150 self::notice($msg);151 exit($exit_code);152 }153 154 function checkArgTyp($arg, $i, $argc, $argv)155 {156 $typ = $this->args[$arg]['typ'];157 158 if (isset($this->typs[$typ]['typ'])) {159 return call_user_func(array($this, $this->typs[$typ]['typ']), $argv[$i], $this->args[$arg], $arg);160 } else {161 return $argv[$i];162 }163 }164 165 static function getSubFuncs(CLICommand $cmdclass, $prefix, array $subs)166 {167 $a = array();168 $r = new ReflectionClass($cmdclass);169 $l = strlen($prefix);170 171 foreach($r->getMethods() as $m) {172 if (substr($m->name, 0, $l) == $prefix) {173 foreach($subs as $sub) {174 $what = substr($m->name, $l+strlen($sub)+1);175 $func = $prefix . $sub . '_' . $what;176 $what = str_replace('_', '-', $what);177 if ($r->hasMethod($func)) {178 if (!isset($a[$what])) {179 $a[$what] = array();180 }181 $a[$what][$sub] = /*$m->class . '::' .*/ $func;182 }183 }184 }185 }186 return $a;187 }188 189 static function getCommands(CLICommand $cmdclass)190 {191 return self::getSubFuncs($cmdclass, 'cli_cmd_', array('arg','inf','run'));192 }193 194 static function getArgTyps(CLICommand $cmdclass)195 {196 return self::getSubFuncs($cmdclass, 'cli_arg_', array('typ'));197 }198 199 static function cli_arg_typ_bool($arg, $cfg, $key)200 {201 return (bool)$arg;202 }203 204 static function cli_arg_typ_int($arg, $cfg, $key)205 {206 if ((int)$arg != $arg) {207 self::error("Argument to -$key must be an integer.\n");208 }209 210 return (int)$arg;211 }212 213 static function cli_arg_typ_regex($arg, $cfg, $key)214 {215 if (strlen($arg)) {216 if (strlen($arg) > 1 && $arg[0] == $arg[strlen($arg)-1] && strpos('/,', $arg) !== false) {217 return $arg;218 } else {219 return '/' . $arg . '/';220 }221 } else {222 return NULL;223 }224 }225 226 static function cli_arg_typ_select($arg, $cfg, $key)227 {228 if (!in_array($arg, array_keys($cfg['select']))) {229 self::error("Parameter value '$arg' not one of '" . join("', '", array_keys($cfg['select'])) . "'.\n");230 }231 return $arg;232 }233 234 static function cli_arg_typ_dir($arg, $cfg, $key)235 {236 $f = realpath($arg);237 238 if ($f===false || !file_exists($f) || !is_dir($f)) {239 self::error("Requested path '$arg' does not exist.\n");240 }241 return $f;242 }243 244 static function cli_arg_typ_file($arg)245 {246 $f = new SplFileInfo($arg);247 $f = $f->getRealPath();248 if ($f===false || !file_exists($f)) {249 echo "Requested file '$arg' does not exist.\n";250 exit(1);251 }252 return $f;253 }254 255 static function cli_arg_typ_filenew($arg, $cfg, $key)256 {257 $d = dirname($arg);258 $f = realpath($d);259 260 if ($f === false) {261 self::error("Path for file '$arg' does not exist.\n");262 }263 return $f . '/' . basename($arg);264 }265 266 static function cli_arg_typ_filecont($arg, $cfg, $key)267 {268 return file_get_contents(self::cli_arg_typ_file($arg, $cfg, $key));269 }270 271 function cli_get_SP2($l1, $arg_inf)272 {273 return str_repeat(' ', $l1 + 2 + 4 + 8);274 }275 276 function cli_get_SP3($l1, $l2, $arg_inf)277 {278 return str_repeat(' ', $l1 + 2 + 4 + 8 + 2 + $l2 + 2);279 }280 281 static function cli_cmd_inf_help()282 {283 return "This help or help for a selected command.";284 }285 286 private function cli_wordwrap($what, $l, $sp)287 {288 $p = max(79 - $l, 40); // minimum length for paragraph289 $b = substr($what, 0, $l); // strip out initial $l290 $r = substr($what, $l); // remainder291 $r = str_replace("\n", "\n".$sp, $r); // in remainder replace \n's292 return $b . wordwrap($r, $p, "\n".$sp);293 }294 295 private function cli_help_get_args($func, $l, $sp, $required)296 {297 $inf = "";298 foreach(call_user_func($func, $l, $sp) as $arg => $conf) {299 if ((isset($conf['required']) && $conf['required']) != $required) {300 continue;301 }302 303 if (strlen($arg)) {304 $arg = "-$arg ";305 } else {306 $arg = "... ";307 }308 309 $sp2 = $this->cli_get_SP2($l, $inf);310 $l2 = strlen($sp2);311 $inf .= $this->cli_wordwrap($sp . $arg . $conf['inf'], $l2, $sp2) . "\n";312 313 if (isset($conf['select']) && count($conf['select'])) {314 $ls = 0;315 foreach($conf['select'] as $opt => $what) {316 $ls = max($ls, strlen($opt));317 }318 $sp3 = $this->cli_get_SP3($l, $ls, $inf);319 $l3 = strlen($sp3);320 foreach($conf['select'] as $opt => $what) {321 $inf .= $this->cli_wordwrap($sp2 . " " . sprintf("%-{$ls}s ", $opt) . $what, $l3, $sp3) . "\n";322 }323 }324 }325 if (strlen($inf)) {326 if ($required) {327 return $sp . "Required arguments:\n\n" . $inf;328 } else {329 return $sp . "Optional arguments:\n\n". $inf;330 }331 }332 }333 334 function cli_cmd_arg_help()335 {336 return array('' => array('typ'=>'any','val'=>NULL,'inf'=>'Optional command to retrieve help for.'));337 }338 339 function cli_cmd_run_help()340 {341 $argv = $this->argv;342 $which = $this->args['']['val'];343 if (isset($which)) {344 if (count($which) != 1) {345 self::error("More than one command given.\n");346 }347 348 $which = $which[0];349 if (!array_key_exists($which, $this->cmds)) {350 if (strtolower($which) == 'commands') {351 self::cli_cmd_run_help_list();352 exit(0);353 }354 self::error("Unknown command, cannot retrieve help.\n");355 }356 357 $l = strlen($which);358 $cmds = array($which => $this->cmds[$which]);359 } else {360 echo "\n$argv[0] <command> [options]\n\n";361 $l = 0;362 ksort($this->cmds);363 foreach($this->cmds as $name => $funcs) {364 $l = max($l, strlen($name));365 }366 $inf = "Commands:";367 $lst = "";368 $ind = strlen($inf) + 1;369 foreach($this->cmds as $name => $funcs) {370 $lst .= ' ' . $name;371 }372 echo $this->cli_wordwrap($inf.$lst, $ind, str_repeat(' ', $ind)) . "\n\n";373 $cmds = $this->cmds;374 }375 $sp = str_repeat(' ', $l + 2);376 foreach($cmds as $name => $funcs) {377 $inf = $name . substr($sp, strlen($name));378 if (isset($funcs['inf'])) {379 $inf .= $this->cli_wordwrap(call_user_func(array($this, $funcs['inf'])), $l, $sp) . "\n";380 if (isset($funcs['arg'])) {381 $inf .= "\n";382 $inf .= $this->cli_help_get_args(array($this, $funcs['arg']), $l, $sp, true);383 $inf .= "\n";384 $inf .= $this->cli_help_get_args(array($this, $funcs['arg']), $l, $sp, false);385 }386 }387 echo "$inf\n\n";388 }389 exit(0);390 }391 392 static function cli_cmd_inf_help_list()393 {394 return "Lists available commands.";395 }396 397 function cli_cmd_run_help_list()398 {399 ksort($this->cmds);400 echo join(' ', array_keys($this->cmds)) . "\n";401 }402}403 404?>405<?php406 407/** @file directorygraphiterator.inc408 * @ingroup Examples409 * @brief class DirectoryGraphIterator410 * @author Marcus Boerger411 * @date 2003 - 2008412 *413 * SPL - Standard PHP Library414 */415 416/** @ingroup Examples417 * @brief A tree iterator that only shows directories.418 * @author Marcus Boerger419 * @version 1.1420 */421class DirectoryGraphIterator extends DirectoryTreeIterator422{423 function __construct($path)424 {425 RecursiveIteratorIterator::__construct(426 new RecursiveCachingIterator(427 new ParentIterator(428 new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::KEY_AS_FILENAME429 )430 ),431 CachingIterator::CALL_TOSTRING|CachingIterator::CATCH_GET_CHILD432 ),433 parent::SELF_FIRST434 );435 }436}437 438?>439<?php440 441/** @file directorytreeiterator.inc442 * @ingroup Examples443 * @brief class DirectoryTreeIterator444 * @author Marcus Boerger445 * @date 2003 - 2008446 *447 * SPL - Standard PHP Library448 */449 450/** @ingroup Examples451 * @brief DirectoryIterator to generate ASCII graphic directory trees452 * @author Marcus Boerger453 * @version 1.1454 */455class DirectoryTreeIterator extends RecursiveIteratorIterator456{457 /** Construct from a path.458 * @param $path directory to iterate459 */460 function __construct($path)461 {462 parent::__construct(463 new RecursiveCachingIterator(464 new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::KEY_AS_FILENAME465 ),466 CachingIterator::CALL_TOSTRING|CachingIterator::CATCH_GET_CHILD467 ),468 parent::SELF_FIRST469 );470 }471 472 /** @return the current element prefixed with ASCII graphics473 */474 function current(): mixed475 {476 $tree = '';477 for ($l=0; $l < $this->getDepth(); $l++) {478 $tree .= $this->getSubIterator($l)->hasNext() ? '| ' : ' ';479 }480 return $tree . ($this->getSubIterator($l)->hasNext() ? '|-' : '\-')481 . $this->getSubIterator($l)->__toString();482 }483 484 /** Aggregates the inner iterator485 */486 function __call($func, $params)487 {488 return call_user_func_array(array($this->getSubIterator(), $func), $params);489 }490}491 492?>493<?php494 495/** @file invertedregexiterator.inc496 * @ingroup Phar497 * @brief class InvertedRegexIterator498 * @author Marcus Boerger499 * @date 2007 - 2008500 *501 * Inverted RegexIterator502 */503 504/** @ingroup Phar505 * @brief Inverted RegexIterator506 * @author Marcus Boerger507 * @version 1.0508 */509class InvertedRegexIterator extends RegexIterator510{511 /** @return !RegexIterator::accept()512 */513 function accept(): bool514 {515 return !RegexIterator::accept();516 }517}518 519?>520<?php521 522/**523 * @file phar.inc524 * @ingroup Phar525 * @brief class Phar526 * @author Marcus Boerger527 * @date 2007 - 2008528 *529 * Phar Command530 */531// {{{ class Phar extends PHP_Archive532/**533 * Phar class534 *535 * @ingroup Phar536 * @brief Phar implementation537 * @author Marcus Boerger538 * @version 1.0539 */540class Phar extends PHP_Archive implements RecursiveIterator541{542 function getSignature()543 {544 return false;545 }546 547 function getAlias()548 {549 return false;550 }551 552 function rewind()553 {554 }555 556 function valid()557 {558 return false;559 }560 561 function current()562 {563 }564 565 function key()566 {567 }568 569 function next()570 {571 }572 573 function hasChildren()574 {575 return false;576 }577 578 function getChildren()579 {580 }581 582 function hasMetadata()583 {584 }585 586 function getMetadata()587 {588 }589 590 function getStub()591 {592 }593 594 function setStub()595 {596 }597}598 599?>600<?php601 602/**603 * @file pharcommand.inc604 * @ingroup Phar605 * @brief class CLICommand606 * @author Marcus Boerger607 * @date 2007 - 2008608 *609 * Phar Command610 */611// {{{ class PharCommand extends CLICommand612/**613 * PharCommand class614 *615 * This class handles the handling of the phar616 * commands. It will be used from command line/console617 * in order to retrieve and execute phar functions.618 *619 * @ingroup Phar620 * @brief Phar console command implementation621 * @author Marcus Boerger622 * @version 1.0623 */624class PharCommand extends CLICommand625{626 // {{{ public function cli_get_SP2627 public function cli_get_SP2($l1, $arg_inf)628 {629 return str_repeat(' ', $l1 + 2 + 4 + 9);630 }631 // }}}632 // {{{ public function cli_get_SP3633 /**634 * Cli Get SP3635 *636 * @param string $l1 Eleven637 * @param string $l2 Twelve638 * @param string $arg_inf639 * @return string The repeated string.640 */641 function cli_get_SP3($l1, $l2, $arg_inf)642 {643 return str_repeat(' ', $l1 + 2 + 4 + 9 + 2 + $l2 + 2);644 }645 // }}}646 // {{{ static function phar_args647 /**648 * Phar arguments649 *650 * This function contains all the phar commands651 *652 * @param string $which Which argument is chosen.653 * @param string $phartype The type of phar, specific file to work on654 * @return unknown655 */656 static function phar_args($which, $phartype)657 {658 $phar_args = array(659 'a' => array(660 'typ' => 'alias',661 'val' => NULL,662 'inf' => '<alias> Provide an alias name for the phar file.'663 ),664 'b' => array(665 'typ' => 'any',666 'val' => NULL,667 'inf' => '<bang> Hash-bang line to start the archive (e.g. #!/usr/bin/php). The hash '668 .' mark itself \'#!\' and the newline character are optional.'669 ),670 'c' => array(671 'typ' => 'compalg',672 'val' => NULL,673 'inf' => '<algo> Compression algorithm.',674 'select' => array(675 '0' => 'No compression',676 'none' => 'No compression',677 'auto' => 'Automatically select compression algorithm'678 )679 ),680 'e' => array(681 'typ' => 'entry',682 'val' => NULL,683 'inf' => '<entry> Name of entry to work on (must include PHAR internal directory name if any).'684 ),685 'f' => array(686 'typ' => $phartype,687 'val' => NULL,688 'inf' => '<file> Specifies the phar file to work on.'689 ),690 'h' => array(691 'typ' => 'select',692 'val' => NULL,693 'inf' => '<method> Selects the hash algorithm.',694 'select' => ['md5' => 'MD5','sha1' => 'SHA1', 'sha256' => 'SHA256', 'sha512' => 'SHA512', 'openssl' => 'OPENSSL', 'openssl_sha256' => 'OPENSSL_SHA256', 'openssl_sha512' => 'OPENSSL_SHA512']695 ),696 'i' => array(697 'typ' => 'regex',698 'val' => NULL,699 'inf' => '<regex> Specifies a regular expression for input files.'700 ),701 'k' => array(702 'typ' => 'any',703 'val' => NULL,704 'inf' => '<index> Subscription index to work on.',705 ),706 'l' => array(707 'typ' => 'int',708 'val' => 0,709 'inf' => '<level> Number of preceding subdirectories to strip from file entries',710 ),711 'm' => array(712 'typ' => 'any',713 'val' => NULL,714 'inf' => '<meta> Meta data to store with entry (serialized php data).'715 ),716 'p' => array(717 'typ' => 'loader',718 'val' => NULL,719 'inf' => '<loader> Location of PHP_Archive class file (pear list-files PHP_Archive).'720 .'You can use \'0\' or \'1\' to locate it automatically using the mentioned '721 .'pear command. When using \'0\' the command does not error out when the '722 .'class file cannot be located. This switch also adds some code around the '723 .'stub so that class PHP_Archive gets registered as phar:// stream wrapper '724 .'if necessary. And finally this switch will add the file phar.inc from '725 .'this package and load it to ensure class Phar is present.'726 ,727 ),728 's' => array(729 'typ' => 'file',730 'val' => NULL,731 'inf' => '<stub> Select the stub file.'732 ),733 'x' => array(734 'typ' => 'regex',735 'val' => NULL,736 'inf' => '<regex> Regular expression for input files to exclude.'737 ),738 'y' => array(739 'typ' => 'privkey',740 'val' => NULL,741 'inf' => '<key> Private key for OpenSSL signing.',742 ),743 );744 745 if (extension_loaded('zlib')) {746 $phar_args['c']['select']['gz'] = 'GZip compression';747 $phar_args['c']['select']['gzip'] = 'GZip compression';748 }749 750 if (extension_loaded('bz2')) {751 $phar_args['c']['select']['bz2'] = 'BZip2 compression';752 $phar_args['c']['select']['bzip2'] = 'BZip2 compression';753 }754 755 $hash_avail = Phar::getSupportedSignatures();756 $hash_optional = array('SHA-256' => 'SHA256',757 'SHA-512' => 'SHA512',758 'OpenSSL_sha256' => 'OpenSSL_SHA256',759 'OpenSSL_sha512' => 'OpenSSL_SHA512',760 'OpenSSL' => 'OpenSSL');761 if (!in_array('OpenSSL', $hash_avail)) {762 unset($phar_args['y']);763 }764 765 foreach($hash_optional as $key => $name) {766 if (in_array($key, $hash_avail)) {767 $phar_args['h']['select'][strtolower($name)] = $name;768 }769 }770 771 $args = array();772 773 foreach($phar_args as $lkey => $cfg) {774 $ukey = strtoupper($lkey);775 $required = strpos($which, $ukey) !== false;776 $optional = strpos($which, $lkey) !== false;777 778 if ($required || $optional) {779 $args[$lkey] = $cfg;780 $args[$lkey]['required'] = $required;781 }782 }783 return $args;784 }785 // }}}786 // {{{ static function strEndsWith787 /**788 * String Ends With789 *790 * Whether a string ends with another needle.791 *792 * @param string $haystack The haystack793 * @param string $needle The needle.794 * @return mixed false if doesn't end with anything, the string795 * substr'ed if the string ends with the needle.796 */797 static function strEndsWith($haystack, $needle)798 {799 return substr($haystack, -strlen($needle)) == $needle;800 }801 // }}}802 // {{{ static function cli_arg_typ_loader803 /**804 * Argument type loader805 *806 * @param string $arg Either 'auto', 'optional' or an filename that807 * contains class PHP_Archive808 * @param string $cfg Configuration to pass to a new file809 * @param string $key The key810 * @return string $arg The argument.811 */812 static function cli_arg_typ_loader($arg, $cfg, $key)813 {814 if (($arg == '0' || $arg == '1') && !file_exists($arg) && substr(PHP_OS, 0, 3) != 'WIN') {815 $found = NULL;816 $apiver = false;817 $path = explode(PATH_SEPARATOR, $_ENV['PATH']);818 $pear = false;819 foreach ($path as $component) {820 if (file_exists($component . DIRECTORY_SEPARATOR . 'pear')821 && is_executable($component . DIRECTORY_SEPARATOR . 'pear')) {822 $pear = true;823 break;824 }825 }826 if ($pear) {827 $apiver = (string) shell_exec("pear -q info PHP_Archive 2>/dev/null|grep 'API Version'");828 $apiver = trim(substr($apiver, strlen('API Version')));829 }830 if ($apiver) {831 self::notice("PEAR package PHP_Archive: API Version: $apiver.\n");832 $files = explode("\n", (string) shell_exec("pear list-files PHP_Archive"));833 $phpdir = (string) shell_exec("pear config-get php_dir 2>/dev/null");834 $phpdir = trim($phpdir);835 self::notice("PEAR package PHP_Archive: $phpdir.\n");836 if (is_dir($phpdir)) {837 foreach($files as $ent) {838 $matches = NULL;839 if (preg_match(",^php[ \t]+([^ \t].*[\\\\/]PHP[\\\\/]Archive\.php)$,", $ent, $matches)) {840 $sub = $matches[1];841 if (strpos($sub, $phpdir) !== 0) {842 $found = NULL;843 break;844 }845 $found = $sub;846 break;847 }848 }849 } else {850 self::notice("PEAR package PHP_Archive: corrupt or inaccessible base dir: $phpdir.\n");851 }852 }853 if (isset($found)) {854 self::notice("PEAR package PHP_Archive: $found.\n");855 } else {856 $msg = "PEAR package PHP_Archive not installed: generated phar will require PHP's phar extension be enabled.\n";857 if ($arg == '0') {858 self::notice($msg);859 } else {860 self::error($msg);861 }862 }863 return null;864 }865 return self::cli_arg_typ_file($arg);866 }867 // }}}868 // {{{ static function cli_arg_typ_pharnew869 /**870 * Argument type new phar871 *872 * @param string $arg The new phar component.873 * @param string $cfg Configuration to pass to a new file874 * @param string $key The key875 * @return string $arg The new argument file.876 */877 static function cli_arg_typ_pharnew($arg, $cfg, $key)878 {879 $arg = self::cli_arg_typ_filenew($arg, $cfg, $key);880 if (!Phar::isValidPharFilename($arg)) {881 self::error("Phar files must have file extension '.phar', '.phar.php', '.phar.bz2' or '.phar.gz'.\n");882 }883 return $arg;884 }885 // }}}886 // {{{ static function cli_arg_typ_pharfile887 /**888 * Argument type existing Phar file889 *890 * Return filename of an existing Phar.891 *892 * @param string $arg The file in the phar to open.893 * @param string $cfg The configuration information894 * @param string $key The key information.895 * @return string $pharfile The name of the loaded Phar file.896 * @note The Phar will be loaded897 */898 static function cli_arg_typ_pharfile($arg, $cfg, $key)899 {900 try {901 $pharfile = self::cli_arg_typ_file($arg, $cfg, $key);902 903 if (!Phar::loadPhar($pharfile)) {904 self::error("Unable to open phar '$arg'\n");905 }906 907 return $pharfile;908 } catch(Exception $e) {909 self::error("Exception while opening phar '$arg':\n" . $e->getMessage() . "\n");910 }911 }912 // }}}913 // {{{ static function cli_arg_typ_pharurl914 /**915 * Argument type Phar url-like916 *917 * Check the argument as cli_arg_Typ_phar and return its name prefixed918 * with phar://919 *920 * Ex:921 * <code>922 * $arg = 'pharchive.phar/file.php';923 * cli_arg_typ_pharurl($arg)924 * </code>925 *926 * @param string $arg The url-like phar archive to retrieve.927 * @return string The phar file-archive.928 */929 static function cli_arg_typ_pharurl($arg, $cfg, $key)930 {931 return 'phar://' . self::cli_arg_typ_pharfile($arg, $cfg, $key);932 }933 // }}}934 // {{{ static function cli_arg_typ_phar935 /**936 * Cli argument type phar937 *938 * @param string $arg The phar archive to use.939 * @return object new Phar of the passed argument.940 */941 static function cli_arg_typ_phar($arg, $cfg, $key)942 {943 try {944 return new Phar(self::cli_arg_typ_pharfile($arg, $cfg, $key));945 } catch(Exception $e) {946 self::error("Exception while opening phar '$argv':\n" . $e->getMessage() . "\n");947 }948 }949 // }}}950 // {{{ static function cli_arg_typ_entry951 /**952 * Argument type Entry name953 *954 * @param string $arg The argument (the entry)955 * @return string $arg The entry itself.956 */957 static function cli_arg_typ_entry($arg, $cfg, $key)958 {959 // no further check atm, maybe check for no '/' at beginning960 return $arg;961 }962 // }}}963 // {{{ static function cli_arg_typ_compalg964 /**965 * Argument type compression algorithm966 *967 * @param string $arg The phar selection968 * @param string $cfg The config option.969 * @param string $key The key information.970 * @return string $arg The selected algorithm971 */972 static function cli_arg_typ_compalg($arg, $cfg, $key)973 {974 $arg = self::cli_arg_typ_select($arg, $cfg, $key);975 976 switch($arg) {977 case 'auto':978 if (extension_loaded('zlib')) {979 $arg = 'gz';980 } elseif (extension_loaded('bz2')) {981 $arg = 'bz2';982 } else {983 $arg = '0';984 }985 break;986 }987 return $arg;988 }989 // }}}990 // {{{ static function cli_arg_typ_privkey991 /**992 * Argument type private key (for OpenSSL signing)993 *994 * @param string $arg The phar selection995 * @param string $cfg The config option.996 * @param string $key The key information.997 * @return string $arg The private key.998 */999 static function cli_arg_typ_privkey($arg, $cfg, $key)1000 {1001 $arg = self::cli_arg_typ_filecont($arg, $cfg, $key);1002 1003 $hash_avail = Phar::getSupportedSignatures();1004 if ($arg && !in_array('OpenSSL', $hash_avail))1005 {1006 self::error("Cannot specify private key without OpenSSL support.\n");1007 }1008 return $arg;1009 }1010 // }}}1011 // {{{ static function phar_check_hash1012 /**1013 * Check whether hash method is valid.1014 *1015 * @return Hash constant to be used.1016 */1017 function phar_check_hash($hash, $privkey)1018 {1019 switch($hash) {1020 case 'md5':1021 return Phar::MD5;1022 case 'sha1':1023 return Phar::SHA1;1024 case 'sha256':1025 return Phar::SHA256;1026 case 'sha512':1027 return Phar::SHA512;1028 case 'openssl':1029 if (!$privkey) {1030 self::error("Cannot use OpenSSL signing without key.\n");1031 }1032 return Phar::OPENSSL;1033 case 'openssl_sha256':1034 if (!$privkey) {1035 self::error("Cannot use OpenSSL signing without key.\n");1036 }1037 return Phar::OPENSSL_SHA256;1038 case 'openssl_sha512':1039 if (!$privkey) {1040 self::error("Cannot use OpenSSL signing without key.\n");1041 }1042 return Phar::OPENSSL_SHA512;1043 }1044 }1045 // }}}1046 // {{{ static function cli_cmd_inf_pack1047 /**1048 * Information pack1049 *1050 * @return string A description about packing files into a Phar archive.1051 */1052 static function cli_cmd_inf_pack()1053 {1054 return "Pack files into a PHAR archive.\n" .1055 "When using -s <stub>, then the stub file is being " .1056 "excluded from the list of input files/dirs." .1057 "To create an archive that contains PEAR class PHP_Archive " .1058 "then point -p argument to PHP/Archive.php.\n";1059 }1060 // }}}1061 // {{{ static function cli_cmd_arg_pack1062 /**1063 * Pack a new phar infos1064 *1065 * @return array $args The arguments for a new Phar archive.1066 */1067 static function cli_cmd_arg_pack()1068 {1069 $args = self::phar_args('abcFhilpsxy', 'pharnew');1070 1071 $args[''] = array(1072 'typ' => 'any',1073 'val' => NULL,1074 'required' => 1,1075 'inf' => ' Any number of input files and directories. If -i is in use then ONLY files and matching the given regular expression are being packed. If -x is given then files matching that regular expression are NOT being packed.',1076 );1077 1078 return $args;1079 }1080 // }}}1081 // {{{ function phar_set_stub_begin1082 /**1083 * Set the stub1084 */1085 public function phar_set_stub_begin(Phar $phar, $stub, $loader = NULL, $hashbang = NULL)1086 {1087 if (isset($stub)) {1088 $c = file_get_contents($stub);1089 1090 if (substr($c, 0, 2) == '#!') {1091 if (strpos($c, "\n") !== false) {1092 if (!isset($hashbang)) {1093 $hashbang = substr($c, 0, strpos($c, "\n") + 1);1094 }1095 $c = substr($c, strpos($c, "\n") + 1);1096 } else {1097 if (!isset($hashbang)) {1098 $hashbang = $c;1099 }1100 $c = NULL;1101 }1102 }1103 1104 if (isset($hashbang)) {1105 if (substr($hashbang, 0, 2) != '#!') {1106 $hashbang = '#!' . $hashbang;1107 }1108 if (substr($hashbang, -1) != "\n") {1109 $hashbang .= "\n";1110 }1111 } else {1112 $hashbang = "";1113 }1114 1115 if (isset($loader)) {1116 $s = "<?php if (!class_exists('PHP_Archive')) {\n?>";1117 if (is_file($loader)) {1118 $s .= file_get_contents($loader);1119 }1120 $s .= "<?php\n";1121 $s .= "}\n";1122 $s .= "if (!in_array('phar', stream_get_wrappers())) {\n";1123 $s .= "\tstream_wrapper_register('phar', 'PHP_Archive');\n";1124 $s .= "}\n";1125 $s .= "if (!class_exists('Phar',0)) {\n";1126 $s .= "\tinclude 'phar://'.__FILE__.'/phar.inc';\n";1127 $s .= "}\n";1128 $s .= '?>';1129 $s .= $c;1130 1131 $phar->setStub($hashbang . $s);1132 } else {1133 $phar->setStub($hashbang . $c);1134 }1135 return new SplFileInfo($stub);1136 }1137 return NULL;1138 }1139 // }}}1140 // {{{ function phar_set_stub_end1141 /**1142 * Set stub end1143 */1144 public function phar_set_stub_end(Phar $phar, $stub, $loader = NULL)1145 {1146 if (isset($stub) && isset($loader)) {1147 if (substr(__FILE__, -15) == 'pharcommand.inc') {1148 self::phar_add_file($phar, 0, 'phar.inc', 'phar://'.__FILE__.'/phar.inc', NULL);1149 } else {1150 self::phar_add_file($phar, 0, 'phar.inc', dirname(__FILE__).'/phar/phar.inc', NULL);1151 }1152 }1153 }1154 // }}}1155 // {{{ function cli_cmd_run_pack1156 /**1157 * Pack a new Phar1158 *1159 * This function will try to pack a new Phar archive.1160 *1161 * @see Exit to make sure that we are done.1162 */1163 public function cli_cmd_run_pack()1164 {1165 if (ini_get('phar.readonly')) {1166 self::error("Creating phar files is disabled by ini setting 'phar.readonly'.\n");1167 }1168 1169 if (!Phar::canWrite()) {1170 self::error("Creating phar files is disabled, Phar::canWrite() returned false.\n");1171 }1172 1173 $alias = $this->args['a']['val'];1174 $hashbang = $this->args['b']['val'];1175 $archive = $this->args['f']['val'];1176 $hash = $this->args['h']['val'];1177 $privkey = $this->args['y']['val'] ?? null;1178 $regex = $this->args['i']['val'];1179 $level = $this->args['l']['val'];1180 $loader = $this->args['p']['val'];1181 $stub = $this->args['s']['val'];1182 $invregex = $this->args['x']['val'];1183 $input = $this->args['']['val'];1184 1185 $hash = self::phar_check_hash($hash, $privkey);1186 1187 $phar = new Phar($archive, 0, $alias);1188 1189 $phar->startBuffering();1190 1191 $stub = $this->phar_set_stub_begin($phar, $stub, $loader, $hashbang);1192 1193 if (!is_array($input)) {1194 $this->phar_add($phar, $level, $input, $regex, $invregex, $stub, NULL, isset($loader));1195 } else {1196 foreach($input as $i) {1197 $this->phar_add($phar, $level, $i, $regex, $invregex, $stub, NULL, isset($loader));1198 }1199 }1200 