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