xref: /PHP-5.5/ext/phar/phar/pharcommand.inc (revision 6de25c15)
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' => 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 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' => '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_filecont($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 the given 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 the given 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: a58a9f060a207c567585aa4858b862d9278df83d $',
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