1<?php 2 3/** 4 * @file pharcommand.inc 5 * @ingroup Phar 6 * @brief class CLICommand 7 * @author Marcus Boerger 8 * @date 2007 - 2008 9 * 10 * Phar Command 11 */ 12// {{{ class PharCommand extends CLICommand 13/** 14 * PharCommand class 15 * 16 * This class handles the handling of the phar 17 * commands. It will be used from command line/console 18 * in order to retrieve and execute phar functions. 19 * 20 * @ingroup Phar 21 * @brief Phar console command implementation 22 * @author Marcus Boerger 23 * @version 1.0 24 */ 25class PharCommand extends CLICommand 26{ 27 // {{{ public function cli_get_SP2 28 public function cli_get_SP2($l1, $arg_inf) 29 { 30 return str_repeat(' ', $l1 + 2 + 4 + 9); 31 } 32 // }}} 33 // {{{ public function cli_get_SP3 34 /** 35 * Cli Get SP3 36 * 37 * @param string $l1 Eleven 38 * @param string $l2 Twelve 39 * @param string $arg_inf 40 * @return string The repeated string. 41 */ 42 function cli_get_SP3($l1, $l2, $arg_inf) 43 { 44 return str_repeat(' ', $l1 + 2 + 4 + 9 + 2 + $l2 + 2); 45 } 46 // }}} 47 // {{{ static function phar_args 48 /** 49 * Phar arguments 50 * 51 * This function contains all the phar commands 52 * 53 * @param string $which Which argument is chosen. 54 * @param string $phartype The type of phar, specific file to work on 55 * @return unknown 56 */ 57 static function phar_args($which, $phartype) 58 { 59 $phar_args = array( 60 'a' => array( 61 'typ' => 'alias', 62 'val' => NULL, 63 'inf' => '<alias> Provide an alias name for the phar file.' 64 ), 65 'b' => array( 66 'typ' => 'any', 67 'val' => NULL, 68 'inf' => '<bang> Hash-bang line to start the archive (e.g. #!/usr/bin/php). The hash ' 69 .' mark itself \'#!\' and the newline character are optional.' 70 ), 71 'c' => array( 72 'typ' => 'compalg', 73 'val' => NULL, 74 'inf' => '<algo> Compression algorithm.', 75 'select' => array( 76 '0' => 'No compression', 77 'none' => 'No compression', 78 'auto' => 'Automatically select compression algorithm' 79 ) 80 ), 81 'e' => array( 82 'typ' => 'entry', 83 'val' => NULL, 84 'inf' => '<entry> Name of entry to work on (must include PHAR internal directory name if any).' 85 ), 86 'f' => array( 87 'typ' => $phartype, 88 'val' => NULL, 89 'inf' => '<file> Specifies the phar file to work on.' 90 ), 91 'h' => array( 92 'typ' => 'select', 93 'val' => NULL, 94 'inf' => '<method> Selects the hash algorithm.', 95 'select' => ['md5' => 'MD5','sha1' => 'SHA1', 'sha256' => 'SHA256', 'sha512' => 'SHA512', 'openssl' => 'OPENSSL', 'openssl_sha256' => 'OPENSSL_SHA256', 'openssl_sha512' => 'OPENSSL_SHA512'] 96 ), 97 'i' => array( 98 'typ' => 'regex', 99 'val' => NULL, 100 'inf' => '<regex> Specifies a regular expression for input files.' 101 ), 102 'k' => array( 103 'typ' => 'any', 104 'val' => NULL, 105 'inf' => '<index> Subscription index to work on.', 106 ), 107 'l' => array( 108 'typ' => 'int', 109 'val' => 0, 110 'inf' => '<level> Number of preceding subdirectories to strip from file entries', 111 ), 112 'm' => array( 113 'typ' => 'any', 114 'val' => NULL, 115 'inf' => '<meta> Meta data to store with entry (serialized php data).' 116 ), 117 'p' => array( 118 'typ' => 'loader', 119 'val' => NULL, 120 'inf' => '<loader> Location of PHP_Archive class file (pear list-files PHP_Archive).' 121 .'You can use \'0\' or \'1\' to locate it automatically using the mentioned ' 122 .'pear command. When using \'0\' the command does not error out when the ' 123 .'class file cannot be located. This switch also adds some code around the ' 124 .'stub so that class PHP_Archive gets registered as phar:// stream wrapper ' 125 .'if necessary. And finally this switch will add the file phar.inc from ' 126 .'this package and load it to ensure class Phar is present.' 127 , 128 ), 129 's' => array( 130 'typ' => 'file', 131 'val' => NULL, 132 'inf' => '<stub> Select the stub file.' 133 ), 134 'x' => array( 135 'typ' => 'regex', 136 'val' => NULL, 137 'inf' => '<regex> Regular expression for input files to exclude.' 138 ), 139 'y' => array( 140 'typ' => 'privkey', 141 'val' => NULL, 142 'inf' => '<key> Private key for OpenSSL signing.', 143 ), 144 ); 145 146 if (extension_loaded('zlib')) { 147 $phar_args['c']['select']['gz'] = 'GZip compression'; 148 $phar_args['c']['select']['gzip'] = 'GZip compression'; 149 } 150 151 if (extension_loaded('bz2')) { 152 $phar_args['c']['select']['bz2'] = 'BZip2 compression'; 153 $phar_args['c']['select']['bzip2'] = 'BZip2 compression'; 154 } 155 156 $hash_avail = Phar::getSupportedSignatures(); 157 $hash_optional = array('SHA-256' => 'SHA256', 158 'SHA-512' => 'SHA512', 159 'OpenSSL_sha256' => 'OpenSSL_SHA256', 160 'OpenSSL_sha512' => 'OpenSSL_SHA512', 161 'OpenSSL' => 'OpenSSL'); 162 if (!in_array('OpenSSL', $hash_avail)) { 163 unset($phar_args['y']); 164 } 165 166 foreach($hash_optional as $key => $name) { 167 if (in_array($key, $hash_avail)) { 168 $phar_args['h']['select'][strtolower($name)] = $name; 169 } 170 } 171 172 $args = array(); 173 174 foreach($phar_args as $lkey => $cfg) { 175 $ukey = strtoupper($lkey); 176 $required = strpos($which, $ukey) !== false; 177 $optional = strpos($which, $lkey) !== false; 178 179 if ($required || $optional) { 180 $args[$lkey] = $cfg; 181 $args[$lkey]['required'] = $required; 182 } 183 } 184 return $args; 185 } 186 // }}} 187 // {{{ static function strEndsWith 188 /** 189 * String Ends With 190 * 191 * Whether a string ends with another needle. 192 * 193 * @param string $haystack The haystack 194 * @param string $needle The needle. 195 * @return mixed false if doesn't end with anything, the string 196 * substr'ed if the string ends with the needle. 197 */ 198 static function strEndsWith($haystack, $needle) 199 { 200 return substr($haystack, -strlen($needle)) == $needle; 201 } 202 // }}} 203 // {{{ static function cli_arg_typ_loader 204 /** 205 * Argument type loader 206 * 207 * @param string $arg Either 'auto', 'optional' or an filename that 208 * contains class PHP_Archive 209 * @param string $cfg Configuration to pass to a new file 210 * @param string $key The key 211 * @return string $arg The argument. 212 */ 213 static function cli_arg_typ_loader($arg, $cfg, $key) 214 { 215 if (($arg == '0' || $arg == '1') && !file_exists($arg) && substr(PHP_OS, 0, 3) != 'WIN') { 216 $found = NULL; 217 $apiver = false; 218 $path = explode(PATH_SEPARATOR, $_ENV['PATH']); 219 $pear = false; 220 foreach ($path as $component) { 221 if (file_exists($component . DIRECTORY_SEPARATOR . 'pear') 222 && is_executable($component . DIRECTORY_SEPARATOR . 'pear')) { 223 $pear = true; 224 break; 225 } 226 } 227 if ($pear) { 228 $apiver = (string) `pear -q info PHP_Archive 2>/dev/null|grep 'API Version'`; 229 $apiver = trim(substr($apiver, strlen('API Version'))); 230 } 231 if ($apiver) { 232 self::notice("PEAR package PHP_Archive: API Version: $apiver.\n"); 233 $files = explode("\n", (string) `pear list-files PHP_Archive`); 234 $phpdir = (string) `pear config-get php_dir 2>/dev/null`; 235 $phpdir = trim($phpdir); 236 self::notice("PEAR package PHP_Archive: $phpdir.\n"); 237 if (is_dir($phpdir)) { 238 foreach($files as $ent) { 239 $matches = NULL; 240 if (preg_match(",^php[ \t]+([^ \t].*[\\\\/]PHP[\\\\/]Archive\.php)$,", $ent, $matches)) { 241 $sub = $matches[1]; 242 if (strpos($sub, $phpdir) !== 0) { 243 $found = NULL; 244 break; 245 } 246 $found = $sub; 247 break; 248 } 249 } 250 } else { 251 self::notice("PEAR package PHP_Archive: corrupt or inaccessible base dir: $phpdir.\n"); 252 } 253 } 254 if (isset($found)) { 255 self::notice("PEAR package PHP_Archive: $found.\n"); 256 } else { 257 $msg = "PEAR package PHP_Archive not installed: generated phar will require PHP's phar extension be enabled.\n"; 258 if ($arg == '0') { 259 self::notice($msg); 260 } else { 261 self::error($msg); 262 } 263 } 264 return null; 265 } 266 return self::cli_arg_typ_file($arg); 267 } 268 // }}} 269 // {{{ static function cli_arg_typ_pharnew 270 /** 271 * Argument type new phar 272 * 273 * @param string $arg The new phar component. 274 * @param string $cfg Configuration to pass to a new file 275 * @param string $key The key 276 * @return string $arg The new argument file. 277 */ 278 static function cli_arg_typ_pharnew($arg, $cfg, $key) 279 { 280 $arg = self::cli_arg_typ_filenew($arg, $cfg, $key); 281 if (!Phar::isValidPharFilename($arg)) { 282 self::error("Phar files must have file extension '.phar', '.phar.php', '.phar.bz2' or '.phar.gz'.\n"); 283 } 284 return $arg; 285 } 286 // }}} 287 // {{{ static function cli_arg_typ_pharfile 288 /** 289 * Argument type existing Phar file 290 * 291 * Return filename of an existing Phar. 292 * 293 * @param string $arg The file in the phar to open. 294 * @param string $cfg The configuration information 295 * @param string $key The key information. 296 * @return string $pharfile The name of the loaded Phar file. 297 * @note The Phar will be loaded 298 */ 299 static function cli_arg_typ_pharfile($arg, $cfg, $key) 300 { 301 try { 302 $pharfile = self::cli_arg_typ_file($arg, $cfg, $key); 303 304 if (!Phar::loadPhar($pharfile)) { 305 self::error("Unable to open phar '$arg'\n"); 306 } 307 308 return $pharfile; 309 } catch(Exception $e) { 310 self::error("Exception while opening phar '$arg':\n" . $e->getMessage() . "\n"); 311 } 312 } 313 // }}} 314 // {{{ static function cli_arg_typ_pharurl 315 /** 316 * Argument type Phar url-like 317 * 318 * Check the argument as cli_arg_Typ_phar and return its name prefixed 319 * with phar:// 320 * 321 * Ex: 322 * <code> 323 * $arg = 'pharchive.phar/file.php'; 324 * cli_arg_typ_pharurl($arg) 325 * </code> 326 * 327 * @param string $arg The url-like phar archive to retrieve. 328 * @return string The phar file-archive. 329 */ 330 static function cli_arg_typ_pharurl($arg, $cfg, $key) 331 { 332 return 'phar://' . self::cli_arg_typ_pharfile($arg, $cfg, $key); 333 } 334 // }}} 335 // {{{ static function cli_arg_typ_phar 336 /** 337 * Cli argument type phar 338 * 339 * @param string $arg The phar archive to use. 340 * @return object new Phar of the passed argument. 341 */ 342 static function cli_arg_typ_phar($arg, $cfg, $key) 343 { 344 try { 345 return new Phar(self::cli_arg_typ_pharfile($arg, $cfg, $key)); 346 } catch(Exception $e) { 347 self::error("Exception while opening phar '$argv':\n" . $e->getMessage() . "\n"); 348 } 349 } 350 // }}} 351 // {{{ static function cli_arg_typ_entry 352 /** 353 * Argument type Entry name 354 * 355 * @param string $arg The argument (the entry) 356 * @return string $arg The entry itself. 357 */ 358 static function cli_arg_typ_entry($arg, $cfg, $key) 359 { 360 // no further check atm, maybe check for no '/' at beginning 361 return $arg; 362 } 363 // }}} 364 // {{{ static function cli_arg_typ_compalg 365 /** 366 * Argument type compression algorithm 367 * 368 * @param string $arg The phar selection 369 * @param string $cfg The config option. 370 * @param string $key The key information. 371 * @return string $arg The selected algorithm 372 */ 373 static function cli_arg_typ_compalg($arg, $cfg, $key) 374 { 375 $arg = self::cli_arg_typ_select($arg, $cfg, $key); 376 377 switch($arg) { 378 case 'auto': 379 if (extension_loaded('zlib')) { 380 $arg = 'gz'; 381 } elseif (extension_loaded('bz2')) { 382 $arg = 'bz2'; 383 } else { 384 $arg = '0'; 385 } 386 break; 387 } 388 return $arg; 389 } 390 // }}} 391 // {{{ static function cli_arg_typ_privkey 392 /** 393 * Argument type private key (for OpenSSL signing) 394 * 395 * @param string $arg The phar selection 396 * @param string $cfg The config option. 397 * @param string $key The key information. 398 * @return string $arg The private key. 399 */ 400 static function cli_arg_typ_privkey($arg, $cfg, $key) 401 { 402 $arg = self::cli_arg_typ_filecont($arg, $cfg, $key); 403 404 $hash_avail = Phar::getSupportedSignatures(); 405 if ($arg && !in_array('OpenSSL', $hash_avail)) 406 { 407 self::error("Cannot specify private key without OpenSSL support.\n"); 408 } 409 return $arg; 410 } 411 // }}} 412 // {{{ static function phar_check_hash 413 /** 414 * Check whether hash method is valid. 415 * 416 * @return Hash constant to be used. 417 */ 418 function phar_check_hash($hash, $privkey) 419 { 420 switch($hash) { 421 case 'md5': 422 return Phar::MD5; 423 case 'sha1': 424 return Phar::SHA1; 425 case 'sha256': 426 return Phar::SHA256; 427 case 'sha512': 428 return Phar::SHA512; 429 case 'openssl': 430 if (!$privkey) { 431 self::error("Cannot use OpenSSL signing without key.\n"); 432 } 433 return Phar::OPENSSL; 434 case 'openssl_sha256': 435 if (!$privkey) { 436 self::error("Cannot use OpenSSL signing without key.\n"); 437 } 438 return Phar::OPENSSL_SHA256; 439 case 'openssl_sha512': 440 if (!$privkey) { 441 self::error("Cannot use OpenSSL signing without key.\n"); 442 } 443 return Phar::OPENSSL_SHA512; 444 } 445 } 446 // }}} 447 // {{{ static function cli_cmd_inf_pack 448 /** 449 * Information pack 450 * 451 * @return string A description about packing files into a Phar archive. 452 */ 453 static function cli_cmd_inf_pack() 454 { 455 return "Pack files into a PHAR archive.\n" . 456 "When using -s <stub>, then the stub file is being " . 457 "excluded from the list of input files/dirs." . 458 "To create an archive that contains PEAR class PHP_Archive " . 459 "then point -p argument to PHP/Archive.php.\n"; 460 } 461 // }}} 462 // {{{ static function cli_cmd_arg_pack 463 /** 464 * Pack a new phar infos 465 * 466 * @return array $args The arguments for a new Phar archive. 467 */ 468 static function cli_cmd_arg_pack() 469 { 470 $args = self::phar_args('abcFhilpsxy', 'pharnew'); 471 472 $args[''] = array( 473 'typ' => 'any', 474 'val' => NULL, 475 'required' => 1, 476 '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.', 477 ); 478 479 return $args; 480 } 481 // }}} 482 // {{{ function phar_set_stub_begin 483 /** 484 * Set the stub 485 */ 486 public function phar_set_stub_begin(Phar $phar, $stub, $loader = NULL, $hashbang = NULL) 487 { 488 if (isset($stub)) { 489 $c = file_get_contents($stub); 490 491 if (substr($c, 0, 2) == '#!') { 492 if (strpos($c, "\n") !== false) { 493 if (!isset($hashbang)) { 494 $hashbang = substr($c, 0, strpos($c, "\n") + 1); 495 } 496 $c = substr($c, strpos($c, "\n") + 1); 497 } else { 498 if (!isset($hashbang)) { 499 $hashbang = $c; 500 } 501 $c = NULL; 502 } 503 } 504 505 if (isset($hashbang)) { 506 if (substr($hashbang, 0, 2) != '#!') { 507 $hashbang = '#!' . $hashbang; 508 } 509 if (substr($hashbang, -1) != "\n") { 510 $hashbang .= "\n"; 511 } 512 } else { 513 $hashbang = ""; 514 } 515 516 if (isset($loader)) { 517 $s = "<?php if (!class_exists('PHP_Archive')) {\n?>"; 518 if (is_file($loader)) { 519 $s .= file_get_contents($loader); 520 } 521 $s .= "<?php\n"; 522 $s .= "}\n"; 523 $s .= "if (!in_array('phar', stream_get_wrappers())) {\n"; 524 $s .= "\tstream_wrapper_register('phar', 'PHP_Archive');\n"; 525 $s .= "}\n"; 526 $s .= "if (!class_exists('Phar',0)) {\n"; 527 $s .= "\tinclude 'phar://'.__FILE__.'/phar.inc';\n"; 528 $s .= "}\n"; 529 $s .= '?>'; 530 $s .= $c; 531 532 $phar->setStub($hashbang . $s); 533 } else { 534 $phar->setStub($hashbang . $c); 535 } 536 return new SplFileInfo($stub); 537 } 538 return NULL; 539 } 540 // }}} 541 // {{{ function phar_set_stub_end 542 /** 543 * Set stub end 544 */ 545 public function phar_set_stub_end(Phar $phar, $stub, $loader = NULL) 546 { 547 if (isset($stub) && isset($loader)) { 548 if (substr(__FILE__, -15) == 'pharcommand.inc') { 549 self::phar_add_file($phar, 0, 'phar.inc', 'phar://'.__FILE__.'/phar.inc', NULL); 550 } else { 551 self::phar_add_file($phar, 0, 'phar.inc', dirname(__FILE__).'/phar/phar.inc', NULL); 552 } 553 } 554 } 555 // }}} 556 // {{{ function cli_cmd_run_pack 557 /** 558 * Pack a new Phar 559 * 560 * This function will try to pack a new Phar archive. 561 * 562 * @see Exit to make sure that we are done. 563 */ 564 public function cli_cmd_run_pack() 565 { 566 if (ini_get('phar.readonly')) { 567 self::error("Creating phar files is disabled by ini setting 'phar.readonly'.\n"); 568 } 569 570 if (!Phar::canWrite()) { 571 self::error("Creating phar files is disabled, Phar::canWrite() returned false.\n"); 572 } 573 574 $alias = $this->args['a']['val']; 575 $hashbang = $this->args['b']['val']; 576 $archive = $this->args['f']['val']; 577 $hash = $this->args['h']['val']; 578 $privkey = $this->args['y']['val'] ?? null; 579 $regex = $this->args['i']['val']; 580 $level = $this->args['l']['val']; 581 $loader = $this->args['p']['val']; 582 $stub = $this->args['s']['val']; 583 $invregex = $this->args['x']['val']; 584 $input = $this->args['']['val']; 585 586 $hash = self::phar_check_hash($hash, $privkey); 587 588 $phar = new Phar($archive, 0, $alias); 589 590 $phar->startBuffering(); 591 592 $stub = $this->phar_set_stub_begin($phar, $stub, $loader, $hashbang); 593 594 if (!is_array($input)) { 595 $this->phar_add($phar, $level, $input, $regex, $invregex, $stub, NULL, isset($loader)); 596 } else { 597 foreach($input as $i) { 598 $this->phar_add($phar, $level, $i, $regex, $invregex, $stub, NULL, isset($loader)); 599 } 600 } 601 602 $this->phar_set_stub_end($phar, $stub, $loader); 603 604 switch($this->args['c']['val']) { 605 case 'gz': 606 case 'gzip': 607 $phar->compressFiles(Phar::GZ); 608 break; 609 case 'bz2': 610 case 'bzip2': 611 $phar->compressFiles(Phar::BZ2); 612 break; 613 default: 614 $phar->decompressFiles(); 615 break; 616 } 617 618 if ($hash) { 619 $phar->setSignatureAlgorithm($hash, $privkey); 620 } 621 622 $phar->stopBuffering(); 623 exit(0); 624 } 625 // }}} 626 // {{{ static function phar_add 627 /** 628 * Add files to a phar archive. 629 * 630 * This function will take a directory and iterate through 631 * it and get the files to insert into the Phar archive. 632 * 633 * @param Phar $phar The phar object. 634 * @param string $input The input directory 635 * @param string $regex The regex used in RegexIterator. 636 * @param string $invregex The InvertedRegexIterator expression. 637 * @param SplFileInfo $stub Stub file object 638 * @param mixed $compress Compression algorithm or NULL 639 * @param boolean $noloader Whether to prevent adding the loader 640 */ 641 static function phar_add(Phar $phar, $level, $input, $regex, $invregex, SplFileInfo $stub = NULL, $compress = NULL, $noloader = false) 642 { 643 if ($input && is_file($input) && !is_dir($input)) { 644 return self::phar_add_file($phar, $level, $input, $input, $compress); 645 } 646 $dir = new RecursiveDirectoryIterator($input); 647 $dir = new RecursiveIteratorIterator($dir); 648 649 if (isset($regex)) { 650 $dir = new RegexIterator($dir, $regex); 651 } 652 653 if (isset($invregex)) { 654 $dir = new InvertedRegexIterator($dir, $invregex); 655 } 656 657 try { 658 foreach($dir as $file) { 659 if ((empty($stub) || $file->getRealPath() != $stub->getRealPath()) && !is_dir($file)) { 660 self::phar_add_file($phar, $level, $dir->getSubPathName(), $file, $compress, $noloader); 661 } 662 } 663 } catch(Exception $e) { 664 self::error("Unable to complete operation on file '$file'\n" . $e->getMessage() . "\n"); 665 } 666 } 667 // }}} 668 // {{{ static function phar_add_file 669 /** 670 * Add a phar file 671 * 672 * This function adds a file to a phar archive. 673 * 674 * @param Phar $phar The phar object 675 * @param string $level The level of the file. 676 * @param string $entry The entry point 677 * @param string $file The file to add to the archive 678 * @param string $compress The compression scheme for the file. 679 * @param boolean $noloader Whether to prevent adding the loader 680 */ 681 static function phar_add_file(Phar $phar, $level, $entry, $file, $compress, $noloader = false) 682 { 683 $entry = str_replace('//', '/', $entry); 684 while($level-- > 0 && ($p = strpos($entry, '/')) !== false) { 685 $entry = substr($entry, $p+1); 686 } 687 688 if ($noloader && $entry == 'phar.inc') { 689 return; 690 } 691 692 echo "$entry\n"; 693 694 $phar[$entry] = file_get_contents($file); 695 switch($compress) { 696 case 'gz': 697 case 'gzip': 698 $phar[$entry]->compress(Phar::GZ); 699 break; 700 case 'bz2': 701 case 'bzip2': 702 $phar[$entry]->compress(Phar::BZ2); 703 break; 704 case '0': 705 $phar[$entry]->decompress(); 706 break; 707 default: 708 break; 709 } 710 } 711 // }}} 712 // {{{ public function phar_dir_echo 713 /** 714 * Echo directory 715 * 716 * @param string $pn 717 * @param unknown_type $f 718 */ 719 public function phar_dir_echo($pn, $f) 720 { 721 echo "$f\n"; 722 } 723 // }}} 724 // {{{ public function phar_dir_operation 725 /** 726 * Directory operations 727 * 728 * Phar directory operations. 729 * 730 * @param RecursiveIteratorIterator $dir The recursiveIteratorIterator object. 731 * @param string $func Function to call on the iterations 732 * @param array $args Function arguments. 733 */ 734 public function phar_dir_operation(RecursiveIteratorIterator $dir, $func, array $args = array()) 735 { 736 $regex = $this->args['i']['val']; 737 $invregex= $this->args['x']['val']; 738 739 if (isset($regex)) { 740 $dir = new RegexIterator($dir, $regex); 741 } 742 743 if (isset($invregex)) { 744 $dir = new InvertedRegexIterator($dir, $invregex); 745 } 746 747 $any = false; 748 foreach($dir as $pn => $f) { 749 $any = true; 750 call_user_func($func, $pn, $f, $args); 751 } 752 return $any; 753 } 754 // {{{ static function cli_cmd_inf_list 755 /** 756 * Cli Command Info List 757 * 758 * @return string What inf does 759 */ 760 static function cli_cmd_inf_list() 761 { 762 return "List contents of a PHAR archive."; 763 } 764 // }}} 765 // {{{ static function cli_cmd_arg_list 766 /** 767 * Cli Command Argument List 768 * 769 * @return arguments list 770 */ 771 static function cli_cmd_arg_list() 772 { 773 return self::phar_args('Fix', 'pharurl'); 774 } 775 // }}} 776 // {{{ public function cli_cmd_run_list 777 /** 778 * Cli Command Run List 779 * 780 * @see $this->phar_dir_operation 781 */ 782 public function cli_cmd_run_list() 783 { 784 $this->phar_dir_operation( 785 new DirectoryTreeIterator( 786 $this->args['f']['val']), 787 array($this, 'phar_dir_echo') 788 ); 789 } 790 // }}} 791 // {{{ static function cli_command_inf_tree 792 /** 793 * Cli Command Inf Tree 794 * 795 * @return string The description of a directory tree for a Phar archive. 796 */ 797 static function cli_cmd_inf_tree() 798 { 799 return "Get a directory tree for a PHAR archive."; 800 } 801 // }}} 802 // {{{ static function cli_cmd_arg_tree 803 /** 804 * Cli Command Argument Tree 805 * 806 * @return string Arguments in URL format. 807 */ 808 static function cli_cmd_arg_tree() 809 { 810 return self::phar_args('Fix', 'pharurl'); 811 } 812 // }}} 813 // {{{ public function cli_cmd_run_tree 814 /** 815 * Cli Command Run Tree 816 * 817 * Set the phar_dir_operation with a directorygraphiterator. 818 * 819 * @see DirectoryGraphIterator 820 * @see $this->phar_dir_operation 821 * 822 */ 823 public function cli_cmd_run_tree() 824 { 825 $a = $this->phar_dir_operation( 826 new DirectoryGraphIterator( 827 $this->args['f']['val']), 828 array($this, 'phar_dir_echo') 829 ); 830 if (!$a) { 831 echo "|-<root directory>\n"; 832 } 833 } 834 // }}} 835 // {{{ cli_cmd_inf_extract 836 /** 837 * Cli Command Inf Extract 838 * 839 * @return string The description of the command extra to a directory. 840 */ 841 static function cli_cmd_inf_extract() 842 { 843 return "Extract a PHAR package to a directory."; 844 } 845 // }}} 846 // {{{ static function cli_cmd_arg_extract 847 /** 848 * Cli Command Arguments Extract 849 * 850 * The arguments for the extract function. 851 * 852 * @return array The arguments for the extraction. 853 */ 854 static function cli_cmd_arg_extract() 855 { 856 $args = self::phar_args('Fix', 'phar'); 857 858 $args[''] = array( 859 'type' => 'dir', 860 'val' => '.', 861 'inf' => ' Directory to extract to (defaults to \'.\').', 862 ); 863 864 return $args; 865 } 866 // }}} 867 // {{{ public function cli_cmd_run_extract 868 /** 869 * Run Extract 870 * 871 * Run the extraction of a phar Archive. 872 * 873 * @see $this->phar_dir_operation 874 */ 875 public function cli_cmd_run_extract() 876 { 877 $dir = $this->args['']['val']; 878 879 if (is_array($dir)) { 880 if (count($dir) != 1) { 881 self::error("Only one target directory allowed.\n"); 882 } else { 883 $dir = $dir[0]; 884 } 885 } 886 887 $phar = $this->args['f']['val']; 888 $base = $phar->getPathname(); 889 $bend = strpos($base, '.phar'); 890 $bend = strpos($base, '/', $bend); 891 $base = substr($base, 0, $bend + 1); 892 $blen = strlen($base); 893 894 $this->phar_dir_operation( 895 new RecursiveIteratorIterator($phar), 896 array($this, 'phar_dir_extract'), 897 array($blen, $dir) 898 ); 899 } 900 // }}} 901 // {{{ public function phar_dir_extract 902 /** 903 * Extract to a directory 904 * 905 * This function will extract the content of a Phar 906 * to a directory and create new files and directories 907 * depending on the permissions on that folder. 908 * 909 * @param string $pn 910 * @param string $f The file name 911 * @param array $args The directory and Blen information 912 */ 913 public function phar_dir_extract($pn, $f, $args) 914 { 915 $blen = $args[0]; 916 $dir = $args[1]; 917 $sub = substr($pn, $blen); 918 $target = $dir . '/' . $sub; 919 920 if (!file_exists(dirname($target))) { 921 @mkdir(dirname($target), 0777, true); 922 } 923 if (!file_exists(dirname($target))) { 924 self::error("Operation could not be completed\n"); 925 } 926 927 echo "$sub"; 928 929 if (!@copy($f, $target)) { 930 echo " ...error\n"; 931 } else { 932 echo " ...ok\n"; 933 } 934 } 935 // }}} 936 // {{{ static function cli_cmd_inf_delete 937 /** 938 * Delete an entry from a phar information. 939 * 940 * @return string The information 941 */ 942 static function cli_cmd_inf_delete() 943 { 944 return 'Delete entry from a PHAR archive'; 945 } 946 // }}} 947 // {{{ static function cli_cmd_arg_delete 948 /** 949 * The cli command argument for deleting. 950 * 951 * @return array information about the arguments to use. 952 */ 953 static function cli_cmd_arg_delete() 954 { 955 return self::phar_args('FE', 'phar'); 956 } 957 // }}} 958 // {{{ public function cli_cmd_run_delete 959 /** 960 * Deleting execution 961 * 962 * Execute the deleting of the file from the phar archive. 963 */ 964 public function cli_cmd_run_delete() 965 { 966 $phar = $this->args['f']['val']; 967 $entry = $this->args['e']['val']; 968 969 $phar->startBuffering(); 970 unset($phar[$entry]); 971 $phar->stopBuffering(); 972 } 973 // }}} 974 // {{{ static function cli_cmd_inf_add 975 /** 976 * Client comment add file information 977 * 978 * @return string The description of the feature 979 */ 980 static function cli_cmd_inf_add() 981 { 982 return "Add entries to a PHAR package."; 983 } 984 // }}} 985 // {{{ static function cli_cmd_arg_add 986 /** 987 * Add a file arguments 988 */ 989 static function cli_cmd_arg_add() 990 { 991 $args = self::phar_args('acFilx', 'phar'); 992 $args[''] = array( 993 'type' => 'any', 994 'val' => NULL, 995 'required' => 1, 996 '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.', 997 ); 998 return $args; 999 } 1000 // }}} 1001 // {{{ public functio cli_cmd_run_add 1002 /** 1003 * Add a file 1004 * 1005 * Run the action of adding a file to 1006 * a phar archive. 1007 */ 1008 public function cli_cmd_run_add() 1009 { 1010 $compress= $this->args['c']['val']; 1011 $phar = $this->args['f']['val']; 1012 $regex = $this->args['i']['val']; 1013 $level = $this->args['l']['val']; 1014 $invregex= $this->args['x']['val']; 1015 $input = $this->args['']['val']; 1016 1017 $phar->startBuffering(); 1018 1019 if (!is_array($input)) { 1020 $this->phar_add($phar, $level, $input, $regex, $invregex, NULL, $compress); 1021 } else { 1022 foreach($input as $i) { 1023 $this->phar_add($phar, $level, $i, $regex, $invregex, NULL, $compress); 1024 } 1025 } 1026 $phar->stopBuffering(); 1027 exit(0); 1028 } 1029 // }}} 1030 // {{{ public function cli_cmd_inf_stub_set 1031 /** 1032 * Set the stup of a phar file. 1033 * 1034 * @return string The stub set description. 1035 */ 1036 public function cli_cmd_inf_stub_set() 1037 { 1038 return "Set the stub of a PHAR file. " . 1039 "If no input file is specified as stub then stdin is being used."; 1040 } 1041 // }}} 1042 // {{{ public function cli_cmd_arg_stub_set 1043 /** 1044 * Set the argument stub 1045 * 1046 * @return string arguments for a stub 1047 */ 1048 public function cli_cmd_arg_stub_set() 1049 { 1050 $args = self::phar_args('bFps', 'phar'); 1051 $args['s']['val'] = 'php://stdin'; 1052 return $args; 1053 } 1054 // }}} 1055 // {{{ public function cli_cmd_run_stub_set 1056 /** 1057 * Cli Command run stub set 1058 * 1059 * @see $phar->setStub() 1060 */ 1061 public function cli_cmd_run_stub_set() 1062 { 1063 $hashbang = $this->args['b']['val']; 1064 $phar = $this->args['f']['val']; 1065 $stub = $this->args['s']['val']; 1066 $loader = $this->args['p']['val']; 1067 1068 $this->phar_set_stub_begin($phar, $stub, $loader, $hashbang); 1069 $this->phar_set_stub_end($phar, $stub, $loader); 1070 } 1071 // }}} 1072 // {{{ public function cli_cmd_inf_stub_get 1073 /** 1074 * Get the command stub infos. 1075 * 1076 * @return string a description of the stub of a Phar file. 1077 */ 1078 public function cli_cmd_inf_stub_get() 1079 { 1080 return "Get the stub of a PHAR file. " . 1081 "If no output file is specified as stub then stdout is being used."; 1082 } 1083 // }}} 1084 // {{{ public function cli_cmd_arg_stub_get 1085 /** 1086 * Get the argument stub 1087 * 1088 * @return array $args The arguments passed to the stub. 1089 */ 1090 public function cli_cmd_arg_stub_get() 1091 { 1092 $args = self::phar_args('Fs', 'phar'); 1093 $args['s']['val'] = 'php://stdin'; 1094 return $args; 1095 } 1096 // }}} 1097 // {{{ public function cli_cmd_run_stub_get 1098 /** 1099 * Cli Command Run Stub 1100 * 1101 * Get arguments and store them into a stub. 1102 * 1103 * @param arguments $args 1104 * @see $this->args 1105 */ 1106 public function cli_cmd_run_stub_get($args) 1107 { 1108 $phar = $this->args['f']['val']; 1109 $stub = $this->args['s']['val']; 1110 1111 file_put_contents($stub, $phar->getStub()); 1112 } 1113 // }}} 1114 // {{{ public function cli_cmd_inf_compress 1115 /** 1116 * Cli Command Inf Compress 1117 * 1118 * Cli Command compress information 1119 * 1120 * @return string A description of the command. 1121 */ 1122 public function cli_cmd_inf_compress() 1123 { 1124 return "Compress or uncompress all files or a selected entry."; 1125 } 1126 // }}} 1127 // {{{ public function cli_cmd_arg_cmpress 1128 /** 1129 * Cli Command Arg Compress 1130 * 1131 * @return array The arguments for compress 1132 */ 1133 public function cli_cmd_arg_compress() 1134 { 1135 return self::phar_args('FCe', 'phar'); 1136 } 1137 // }}} 1138 // {{{ public function cli_cmd_run_compress 1139 /** 1140 * Cli Command Run Compress 1141 * 1142 * @see $this->args 1143 */ 1144 public function cli_cmd_run_compress() 1145 { 1146 $phar = $this->args['f']['val']; 1147 $entry = $this->args['e']['val']; 1148 1149 switch($this->args['c']['val']) { 1150 case 'gz': 1151 case 'gzip': 1152 if (isset($entry)) { 1153 $phar[$entry]->compress(Phar::GZ); 1154 } else { 1155 $phar->compressFiles(Phar::GZ); 1156 } 1157 break; 1158 case 'bz2': 1159 case 'bzip2': 1160 if (isset($entry)) { 1161 $phar[$entry]->compress(Phar::BZ2); 1162 } else { 1163 $phar->compressFiles(Phar::BZ2); 1164 } 1165 break; 1166 default: 1167 if (isset($entry)) { 1168 $phar[$entry]->decompress(); 1169 } else { 1170 $phar->decompressFiles(); 1171 } 1172 break; 1173 } 1174 } 1175 // }}} 1176 // {{{ public function cli_cmd_inf_sign 1177 /** 1178 * Cli Command Info Signature 1179 * 1180 * @return string A description of the signature arguments. 1181 */ 1182 public function cli_cmd_inf_sign() 1183 { 1184 return "Set signature hash algorithm."; 1185 } 1186 // }}} 1187 // {{{ public function cli_cmd_arg_sign 1188 /** 1189 * Cli Command Argument Sign 1190 * 1191 * @return array Arguments for Signature 1192 */ 1193 public function cli_cmd_arg_sign() 1194 { 1195 return self::phar_args('FHy', 'phar'); 1196 } 1197 // }}} 1198 // {{{ public function cli_cmd_run_sign 1199 /** 1200 * Cli Command Run Signature 1201 * 1202 * @see $phar->setSignaturealgorithm 1203 */ 1204 public function cli_cmd_run_sign() 1205 { 1206 $phar = $this->args['f']['val']; 1207 $hash = $this->args['h']['val']; 1208 $privkey = $this->args['y']['val']; 1209 1210 $hash = self::phar_check_hash($hash, $privkey); 1211 1212 $phar->setSignatureAlgorithm($hash, $privkey); 1213 } 1214 // }}} 1215 // {{{ public function cli_cmd_inf_meta_set 1216 /** 1217 * Cli Command Inf Meta Set 1218 * 1219 * @return string A description 1220 */ 1221 public function cli_cmd_inf_meta_set() 1222 { 1223 return "Set meta data of a PHAR entry or a PHAR package using serialized input. " . 1224 "If no input file is specified for meta data then stdin is being used." . 1225 "You can also specify a particular index using -k. In that case the metadata is " . 1226 "expected to be an array and the value of the given index is being set. If " . 1227 "the metadata is not present or empty a new array will be created. If the " . 1228 "metadata is present and a flat value then the return value is 1. Also using -k " . 1229 "the input is been taken directly rather then being serialized."; 1230 } 1231 // }}} 1232 // {{{ public function cli_cmd_arg_meta_set 1233 /** 1234 * Cli Command Argument Meta Set 1235 * 1236 * @return array The arguments for meta set 1237 */ 1238 public function cli_cmd_arg_meta_set() 1239 { 1240 return self::phar_args('FekM', 'phar'); 1241 } 1242 // }}} 1243 // {{{ public function cli_cmd_run_met_set 1244 /** 1245 * Cli Command Run Metaset 1246 * 1247 * @see $phar->startBuffering 1248 * @see $phar->setMetadata 1249 * @see $phar->stopBuffering 1250 */ 1251 public function cli_cmd_run_meta_set() 1252 { 1253 $phar = $this->args['f']['val']; 1254 $entry = $this->args['e']['val']; 1255 $index = $this->args['k']['val']; 1256 $meta = $this->args['m']['val']; 1257 1258 $phar->startBuffering(); 1259 1260 if (isset($index)) { 1261 if (isset($entry)) { 1262 if ($phar[$entry]->hasMetadata()) { 1263 $old = $phar[$entry]->getMetadata(); 1264 } else { 1265 $old = array(); 1266 } 1267 } else { 1268 if ($phar->hasMetadata()) { 1269 $old = $phar->getMetadata(); 1270 } else { 1271 $old = array(); 1272 } 1273 } 1274 1275 if (!is_array($old)) { 1276 self::error('Metadata is a flat value while an index operation was issued.'); 1277 } 1278 1279 $old[$index] = $meta; 1280 $meta = $old; 1281 } else { 1282 $meta = unserialize($meta); 1283 } 1284 1285 if (isset($entry)) { 1286 $phar[$entry]->setMetadata($meta); 1287 } else { 1288 $phar->setMetadata($meta); 1289 } 1290 $phar->stopBuffering(); 1291 } 1292 // }}} 1293 // {{{ public function cli_cmd_inf_met_get 1294 /** 1295 * Cli Command Inf Metaget 1296 * 1297 * @return string A description of the metaget arguments 1298 */ 1299 public function cli_cmd_inf_meta_get() 1300 { 1301 return "Get meta information of a PHAR entry or a PHAR package in serialized from. " . 1302 "If no output file is specified for meta data then stdout is being used.\n" . 1303 "You can also specify a particular index using -k. In that case the metadata is " . 1304 "expected to be an array and the value of the given index is returned using echo " . 1305 "rather than using serialize. If that index does not exist or no meta data is " . 1306 "present then the return value is 1."; 1307 } 1308 // }}} 1309 // {{{ public function cli_cmd_arg_meta_get 1310 /** 1311 * Cli Command arg metaget 1312 * 1313 * @return array The arguments for meta get. 1314 */ 1315 public function cli_cmd_arg_meta_get() 1316 { 1317 return self::phar_args('Fek', 'phar'); 1318 } 1319 // }}} 1320 // {{{ public function cli_cmd_run_meta_get 1321 /** 1322 * Cli Command Run Metaget 1323 * 1324 * @see $this->args 1325 * @see $phar[$x]->hasMetadata() 1326 * @see $phar->getMetadata() 1327 */ 1328 public function cli_cmd_run_meta_get() 1329 { 1330 $phar = $this->args['f']['val']; 1331 $entry = $this->args['e']['val']; 1332 $index = $this->args['k']['val']; 1333 1334 if (isset($entry)) { 1335 if (!$phar[$entry]->hasMetadata()) { 1336 echo "No Metadata\n"; 1337 exit(1); 1338 } 1339 echo serialize($phar[$entry]->getMetadata()); 1340 } else { 1341 if (!$phar->hasMetadata()) { 1342 echo "No Metadata\n"; 1343 exit(1); 1344 } 1345 $meta = $phar->getMetadata(); 1346 } 1347 1348 if (isset($index)) { 1349 if (isset($index)) { 1350 if (isset($meta[$index])) { 1351 echo $meta[$index]; 1352 exit(0); 1353 } else { 1354 echo "No Metadata\n"; 1355 exit(1); 1356 } 1357 } else { 1358 echo serialize($meta); 1359 } 1360 } 1361 } 1362 // }}} 1363 // {{{ public function cli_cmd_inf_meta_del 1364 /** 1365 * Cli Command Inf Metadel 1366 * 1367 * @return string A description of the metadel function 1368 */ 1369 public function cli_cmd_inf_meta_del() 1370 { 1371 return "Delete meta information of a PHAR entry or a PHAR package.\n" . 1372 "If -k is given then the metadata is expected to be an array " . 1373 "and the given index is being deleted.\n" . 1374 "If something was deleted the return value is 0 otherwise it is 1."; 1375 } 1376 // }}} 1377 // {{{ public function cli_cmd_arg_meta_del 1378 /** 1379 * CliC ommand Arg Metadelete 1380 * 1381 * @return array The arguments for metadel 1382 */ 1383 public function cli_cmd_arg_meta_del() 1384 { 1385 return self::phar_args('Fek', 'phar'); 1386 } 1387 // }}} 1388 // {{{ public function cli_cmd_run_meta_del 1389 /** 1390 * Cli Command Run MetaDel 1391 * 1392 * @see $phar[$x]->delMetadata() 1393 * @see $phar->delMetadata() 1394 */ 1395 public function cli_cmd_run_meta_del() 1396 { 1397 $phar = $this->args['f']['val']; 1398 $entry = $this->args['e']['val']; 1399 $index = $this->args['k']['val']; 1400 1401 if (isset($entry)) { 1402 if (isset($index)) { 1403 if (!$phar[$entry]->hasMetadata()) { 1404 exit(1); 1405 } 1406 $meta = $phar[$entry]->getMetadata(); 1407 1408 // @todo add error message here. 1409 if (!is_array($meta)) { 1410 exit(1); 1411 } 1412 1413 unset($meta[$index]); 1414 $phar[$entry]->setMetadata($meta); 1415 } else { 1416 exit($phar[$entry]->delMetadata() ? 0 : 1); 1417 } 1418 } else { 1419 if (isset($index)) { 1420 if (!$phar->hasMetadata()) { 1421 exit(1); 1422 } 1423 1424 $meta = $phar->getMetadata(); 1425 1426 // @todo Add error message 1427 if (!is_array($meta)) { 1428 exit(1); 1429 } 1430 1431 unset($meta[$index]); 1432 $phar->setMetadata($meta); 1433 } else { 1434 exit($phar->delMetadata() ? 0 : 1); 1435 } 1436 } 1437 } 1438 // }}} 1439 // {{{ public function cli_cmd_inf_info 1440 /** 1441 * CLi Command Inf Info 1442 * 1443 * @return string A description about the info commands. 1444 */ 1445 public function cli_cmd_inf_info() 1446 { 1447 return "Get information about a PHAR package.\n" . 1448 "By using -k it is possible to return a single value."; 1449 } 1450 // }}} 1451 // {{{ public function cli_cmd_arg_info 1452 /** 1453 * Cli Command Arg Infos 1454 * 1455 * @return array The arguments for info command. 1456 */ 1457 public function cli_cmd_arg_info() 1458 { 1459 return self::phar_args('Fk', 'phar'); 1460 } 1461 // }}} 1462 // {{{ public function cli_cmd_run_info 1463 /** 1464 * Cli Command Run Info 1465 * 1466 * @param args $args 1467 */ 1468 public function cli_cmd_run_info() 1469 { 1470 $phar = $this->args['f']['val']; 1471 $index = $this->args['k']['val']; 1472 1473 $hash = $phar->getSignature(); 1474 $infos = array(); 1475 1476 if ($phar->getAlias()) { 1477 $infos['Alias'] = $phar->getAlias(); 1478 } 1479 1480 if (!$hash) { 1481 $infos['Hash-type'] = 'NONE'; 1482 } else { 1483 $infos['Hash-type'] = $hash['hash_type']; 1484 $infos['Hash'] = $hash['hash']; 1485 } 1486 1487 $csize = 0; 1488 $usize = 0; 1489 $count = 0; 1490 $ccount = 0; 1491 $ucount = 0; 1492 $mcount = 0; 1493 $compalg = array('GZ'=>0, 'BZ2'=>0); 1494 1495 foreach(new RecursiveIteratorIterator($phar) as $ent) { 1496 $count++; 1497 if ($ent->isCompressed()) { 1498 $ccount++; 1499 $csize += $ent->getCompressedSize(); 1500 if ($ent->isCompressed(Phar::GZ)) { 1501 $compalg['GZ']++; 1502 } elseif ($ent->isCompressed(Phar::BZ2)) { 1503 $compalg['BZ2']++; 1504 } 1505 } else { 1506 $ucount++; 1507 $csize += $ent->getSize(); 1508 } 1509 1510 $usize += $ent->getSize(); 1511 1512 if ($ent->hasMetadata()) { 1513 $mcount++; 1514 } 1515 } 1516 1517 $infos['Entries'] = $count; 1518 $infos['Uncompressed-files'] = $ucount; 1519 $infos['Compressed-files'] = $ccount; 1520 $infos['Compressed-gz'] = $compalg['GZ']; 1521 $infos['Compressed-bz2'] = $compalg['BZ2']; 1522 $infos['Uncompressed-size'] = $usize; 1523 $infos['Compressed-size'] = $csize; 1524 $infos['Compression-ratio'] = sprintf('%.3g%%', $usize ? ($csize * 100) / $usize : 100); 1525 $infos['Metadata-global'] = $phar->hasMetadata() * 1; 1526 $infos['Metadata-files'] = $mcount; 1527 $infos['Stub-size'] = strlen($phar->getStub()); 1528 1529 if (isset($index)) { 1530 if (!isset($infos[$index])) { 1531 self::error("Requested value does not exist.\n"); 1532 } 1533 1534 echo $infos[$index]; 1535 exit(0); 1536 } 1537 1538 $l = 0; 1539 foreach($infos as $which => $val) { 1540 $l = max(strlen($which), $l); 1541 } 1542 1543 foreach($infos as $which => $val) { 1544 echo $which . ':' . str_repeat(' ', $l + 1 - strlen($which)) . $val . "\n"; 1545 } 1546 } 1547 // }}} 1548 // {{{ public function cli_cmd_inf_version 1549 /** 1550 * CLi Command Inf Version 1551 * 1552 * @return string A description about the info commands. 1553 */ 1554 public function cli_cmd_inf_version() 1555 { 1556 return "Get information about the PHAR environment and the tool version."; 1557 } 1558 // }}} 1559 // {{{ public function cli_cmd_arg_version 1560 /** 1561 * Cli Command Arg Version 1562 * 1563 * @return array The arguments for version command. 1564 */ 1565 public function cli_cmd_arg_version() 1566 { 1567 return self::phar_args('', NULL); 1568 } 1569 // }}} 1570 // {{{ public function cli_cmd_run_info 1571 /** 1572 * Cli Command Run Info 1573 * 1574 * @param args $args 1575 */ 1576 public function cli_cmd_run_version() 1577 { 1578 $use_ext = extension_loaded('phar'); 1579 $version = array( 1580 'PHP Version' => phpversion(), 1581 'phar.phar version' => '$Id: fdc43654dd7eb031236df3c45ad54a6ec9454316 $', 1582 'Phar EXT version' => $use_ext ? phpversion('phar') : 'Not available', 1583 'Phar API version' => Phar::apiVersion(), 1584 'Phar-based phar archives' => true, 1585 'Tar-based phar archives' => $use_ext, 1586 'ZIP-based phar archives' => $use_ext, 1587 'gzip compression' => extension_loaded('zlib'), 1588 'bzip2 compression' => extension_loaded('bz2'), 1589 'supported signatures' => $use_ext ? join(', ', Phar::getSupportedSignatures()) : '', 1590 ); 1591 $klen = 0; 1592 foreach($version as $k => $v) 1593 { 1594 $klen = max($klen, strlen($k)); 1595 } 1596 ++$klen; 1597 foreach($version as $k => $v) { 1598 if (is_bool($v)) { 1599 $v = $v ? 'enabled' : 'disabled'; 1600 } 1601 printf("%-{$klen}s %s\n", $k.':', $v); 1602 } 1603 } 1604 // }}} 1605} 1606// }}} 1607?> 1608