--- /dev/null
+#!/usr/bin/php
+<?php if (!class_exists('PHP_Archive')) {
+?><?php
+/**
+ * PHP_Archive Class (implements .phar)
+ *
+ * @package PHP_Archive
+ * @category PHP
+ */
+/**
+ * PHP_Archive Class (implements .phar)
+ *
+ * PHAR files a singular archive from which an entire application can run.
+ * To use it, simply package it using {@see PHP_Archive_Creator} and use phar://
+ * URIs to your includes. i.e. require_once 'phar://config.php' will include config.php
+ * from the root of the PHAR file.
+ *
+ * Gz code borrowed from the excellent File_Archive package by Vincent Lascaux.
+ *
+ * @copyright Copyright David Shafik and Synaptic Media 2004. All rights reserved.
+ * @author Davey Shafik <davey@synapticmedia.net>
+ * @author Greg Beaver <cellog@php.net>
+ * @link http://www.synapticmedia.net Synaptic Media
+ * @version $Id: Archive.php,v 1.43 2007/05/28 18:20:40 helly Exp $
+ * @package PHP_Archive
+ * @category PHP
+ */
+
+class PHP_Archive
+{
+ const GZ = 0x00001000;
+ const BZ2 = 0x00002000;
+ const SIG = 0x00010000;
+ const SHA1 = 0x0002;
+ const MD5 = 0x0001;
+ /**
+ * Whether this archive is compressed with zlib
+ *
+ * @var bool
+ */
+ private $_compressed;
+ /**
+ * @var string Real path to the .phar archive
+ */
+ private $_archiveName = null;
+ /**
+ * Current file name in the phar
+ * @var string
+ */
+ protected $currentFilename = null;
+ /**
+ * Length of current file in the phar
+ * @var string
+ */
+ protected $internalFileLength = null;
+ /**
+ * Current file statistics (size, creation date, etc.)
+ * @var string
+ */
+ protected $currentStat = null;
+ /**
+ * @var resource|null Pointer to open .phar
+ */
+ protected $fp = null;
+ /**
+ * @var int Current Position of the pointer
+ */
+ protected $position = 0;
+
+ /**
+ * Map actual realpath of phars to meta-data about the phar
+ *
+ * Data is indexed by the alias that is used by internal files. In other
+ * words, if a file is included via:
+ * <code>
+ * require_once 'phar://PEAR.phar/PEAR/Installer.php';
+ * </code>
+ * then the alias is "PEAR.phar"
+ *
+ * Information stored is a boolean indicating whether this .phar is compressed
+ * with zlib, another for bzip2, phar-specific meta-data, and
+ * the precise offset of internal files
+ * within the .phar, used with the {@link $_manifest} to load actual file contents
+ * @var array
+ */
+ private static $_pharMapping = array();
+ /**
+ * Map real file paths to alias used
+ *
+ * @var array
+ */
+ private static $_pharFiles = array();
+ /**
+ * File listing for the .phar
+ *
+ * The manifest is indexed per phar.
+ *
+ * Files within the .phar are indexed by their relative path within the
+ * .phar. Each file has this information in its internal array
+ *
+ * - 0 = uncompressed file size
+ * - 1 = timestamp of when file was added to phar
+ * - 2 = offset of file within phar relative to internal file's start
+ * - 3 = compressed file size (actual size in the phar)
+ * @var array
+ */
+ private static $_manifest = array();
+ /**
+ * Absolute offset of internal files within the .phar, indexed by absolute
+ * path to the .phar
+ *
+ * @var array
+ */
+ private static $_fileStart = array();
+ /**
+ * file name of the phar
+ *
+ * @var string
+ */
+ private $_basename;
+
+
+ /**
+ * Default MIME types used for the web front controller
+ *
+ * @var array
+ */
+ public static $defaultmimes = array(
+ 'aif' => 'audio/x-aiff',
+ 'aiff' => 'audio/x-aiff',
+ 'arc' => 'application/octet-stream',
+ 'arj' => 'application/octet-stream',
+ 'art' => 'image/x-jg',
+ 'asf' => 'video/x-ms-asf',
+ 'asx' => 'video/x-ms-asf',
+ 'avi' => 'video/avi',
+ 'bin' => 'application/octet-stream',
+ 'bm' => 'image/bmp',
+ 'bmp' => 'image/bmp',
+ 'bz2' => 'application/x-bzip2',
+ 'css' => 'text/css',
+ 'doc' => 'application/msword',
+ 'dot' => 'application/msword',
+ 'dv' => 'video/x-dv',
+ 'dvi' => 'application/x-dvi',
+ 'eps' => 'application/postscript',
+ 'exe' => 'application/octet-stream',
+ 'gif' => 'image/gif',
+ 'gz' => 'application/x-gzip',
+ 'gzip' => 'application/x-gzip',
+ 'htm' => 'text/html',
+ 'html' => 'text/html',
+ 'ico' => 'image/x-icon',
+ 'jpe' => 'image/jpeg',
+ 'jpg' => 'image/jpeg',
+ 'jpeg' => 'image/jpeg',
+ 'js' => 'application/x-javascript',
+ 'log' => 'text/plain',
+ 'mid' => 'audio/x-midi',
+ 'mov' => 'video/quicktime',
+ 'mp2' => 'audio/mpeg',
+ 'mp3' => 'audio/mpeg3',
+ 'mpg' => 'audio/mpeg',
+ 'pdf' => 'aplication/pdf',
+ 'png' => 'image/png',
+ 'rtf' => 'application/rtf',
+ 'tif' => 'image/tiff',
+ 'tiff' => 'image/tiff',
+ 'txt' => 'text/plain',
+ 'xml' => 'text/xml',
+ );
+
+ public static $defaultphp = array(
+ 'php' => true
+ );
+
+ public static $defaultphps = array(
+ 'phps' => true
+ );
+
+ public static $deny = array('/.+\.inc$/');
+
+ public static function viewSource($archive, $file)
+ {
+ // security, idea borrowed from PHK
+ if (!file_exists($archive . '.introspect')) {
+ header("HTTP/1.0 404 Not Found");
+ exit;
+ }
+ if (self::_fileExists($archive, $_GET['viewsource'])) {
+ $source = highlight_file('phar://@ALIAS@/' .
+ $_GET['viewsource'], true);
+ header('Content-Type: text/html');
+ header('Content-Length: ' . strlen($source));
+ echo '<html><head><title>Source of ',
+ htmlspecialchars($_GET['viewsource']), '</title></head>';
+ echo '<body><h1>Source of ',
+ htmlspecialchars($_GET['viewsource']), '</h1>';
+ if (isset($_GET['introspect'])) {
+ echo '<a href="', htmlspecialchars($_SERVER['PHP_SELF']),
+ '?introspect=', urlencode(htmlspecialchars($_GET['introspect'])),
+ '">Return to ', htmlspecialchars($_GET['introspect']), '</a><br />';
+ }
+ echo $source;
+ exit;
+ } else {
+ header("HTTP/1.0 404 Not Found");
+ exit;
+ }
+
+ }
+
+ public static function introspect($archive, $dir)
+ {
+ // security, idea borrowed from PHK
+ if (!file_exists($archive . '.introspect')) {
+ header("HTTP/1.0 404 Not Found");
+ exit;
+ }
+ if (!$dir) {
+ $dir = '/';
+ }
+ $dir = self::processFile($dir);
+ if ($dir[0] != '/') {
+ $dir = '/' . $dir;
+ }
+ try {
+ $self = htmlspecialchars($_SERVER['PHP_SELF']);
+ $iterate = new DirectoryIterator('phar://@ALIAS@' . $dir);
+ echo '<html><head><title>Introspect ', htmlspecialchars($dir),
+ '</title></head><body><h1>Introspect ', htmlspecialchars($dir),
+ '</h1><ul>';
+ if ($dir != '/') {
+ echo '<li><a href="', $self, '?introspect=',
+ htmlspecialchars(dirname($dir)), '">..</a></li>';
+ }
+ foreach ($iterate as $entry) {
+ if ($entry->isDot()) continue;
+ $name = self::processFile($entry->getPathname());
+ $name = str_replace('phar://@ALIAS@/', '', $name);
+ if ($entry->isDir()) {
+ echo '<li><a href="', $self, '?introspect=',
+ urlencode(htmlspecialchars($name)),
+ '">',
+ htmlspecialchars($entry->getFilename()), '/</a> [directory]</li>';
+ } else {
+ echo '<li><a href="', $self, '?introspect=',
+ urlencode(htmlspecialchars($dir)), '&viewsource=',
+ urlencode(htmlspecialchars($name)),
+ '">',
+ htmlspecialchars($entry->getFilename()), '</a></li>';
+ }
+ }
+ exit;
+ } catch (Exception $e) {
+ echo '<html><head><title>Directory not found: ',
+ htmlspecialchars($dir), '</title></head>',
+ '<body><h1>Directory not found: ', htmlspecialchars($dir), '</h1>',
+ '<p>Try <a href="', htmlspecialchars($_SERVER['PHP_SELF']), '?introspect=/">',
+ 'This link</a></p></body></html>';
+ exit;
+ }
+ }
+
+ public static function webFrontController($initfile)
+ {
+ if (isset($_SERVER) && isset($_SERVER['REQUEST_URI'])) {
+ $uri = parse_url($_SERVER['REQUEST_URI']);
+ $archive = realpath($_SERVER['SCRIPT_FILENAME']);
+ $subpath = str_replace('/' . basename($archive), '', $uri['path']);
+ if (!$subpath || $subpath == '/') {
+ if (isset($_GET['viewsource'])) {
+ self::viewSource($archive, $_GET['viewsource']);
+ }
+ if (isset($_GET['introspect'])) {
+ self::introspect($archive, $_GET['introspect']);
+ }
+ $subpath = '/' . $initfile;
+ }
+ if (!self::_fileExists($archive, substr($subpath, 1))) {
+ header("HTTP/1.0 404 Not Found");
+ exit;
+ }
+ foreach (self::$deny as $pattern) {
+ if (preg_match($pattern, $subpath)) {
+ header("HTTP/1.0 404 Not Found");
+ exit;
+ }
+ }
+ $inf = pathinfo(basename($subpath));
+ if (!isset($inf['extension'])) {
+ header('Content-Type: text/plain');
+ header('Content-Length: ' .
+ self::_filesize($archive, substr($subpath, 1)));
+ readfile('phar://@ALIAS@' . $subpath);
+ exit;
+ }
+ if (isset(self::$defaultphp[$inf['extension']])) {
+ include 'phar://@ALIAS@' . $subpath;
+ exit;
+ }
+ if (isset(self::$defaultmimes[$inf['extension']])) {
+ header('Content-Type: ' . self::$defaultmimes[$inf['extension']]);
+ header('Content-Length: ' .
+ self::_filesize($archive, substr($subpath, 1)));
+ readfile('phar://@ALIAS@' . $subpath);
+ exit;
+ }
+ if (isset(self::$defaultphps[$inf['extension']])) {
+ header('Content-Type: text/html');
+ $c = highlight_file('phar://@ALIAS@' . $subpath, true);
+ header('Content-Length: ' . strlen($c));
+ echo $c;
+ exit;
+ }
+ header('Content-Type: text/plain');
+ header('Content-Length: ' .
+ self::_filesize($archive, substr($subpath, 1)));
+ readfile('phar://@ALIAS@' . $subpath);
+ exit;
+ }
+ }
+
+ /**
+ * Detect end of stub
+ *
+ * @param string $buffer stub past '__HALT_'.'COMPILER();'
+ * @return end of stub, prior to length of manifest.
+ */
+ private static final function _endOfStubLength($buffer)
+ {
+ $pos = 0;
+ if (($buffer[0] == ' ' || $buffer[0] == "\n") && substr($buffer, 1, 2) == '?>')
+ {
+ $pos += 3;
+ if ($buffer[$pos] == "\r" && $buffer[$pos+1] == "\n") {
+ $pos += 2;
+ }
+ else if ($buffer[$pos] == "\n") {
+ $pos += 1;
+ }
+ }
+ return $pos;
+ }
+
+ /**
+ * Allows loading an external Phar archive without include()ing it
+ *
+ * @param string $file phar package to load
+ * @param string $alias alias to use
+ * @throws Exception
+ */
+ public static final function loadPhar($file, $alias = NULL)
+ {
+ $file = realpath($file);
+ if ($file) {
+ $fp = fopen($file, 'rb');
+ $buffer = '';
+ while (!$found && !feof($fp)) {
+ $buffer .= fread($fp, 8192);
+ // don't break phars
+ if ($pos = strpos($buffer, '__HALT_COMPI' . 'LER();')) {
+ $buffer .= fread($fp, 5);
+ fclose($fp);
+ $pos += 18;
+ $pos += self::_endOfStubLength(substr($buffer, $pos));
+ return self::_mapPhar($file, $pos, $alias);
+ }
+ }
+ fclose($fp);
+ }
+ }
+
+ /**
+ * Map a full real file path to an alias used to refer to the .phar
+ *
+ * This function can only be called from the initialization of the .phar itself.
+ * Any attempt to call from outside the .phar or to re-alias the .phar will fail
+ * as a security measure.
+ * @param string $alias
+ * @param int $dataoffset the value of __COMPILER_HALT_OFFSET__
+ */
+ public static final function mapPhar($alias = NULL, $dataoffset = NULL)
+ {
+ try {
+ $file = __FILE__;
+ // this ensures that this is safe
+ if (!in_array($file, get_included_files())) {
+ die('SECURITY ERROR: PHP_Archive::mapPhar can only be called from within ' .
+ 'the phar that initiates it');
+ }
+ if (!isset($dataoffset)) {
+ $dataoffset = constant('__COMPILER_HALT_OFFSET'.'__');
+ }
+ $file = realpath($file);
+
+ $fp = fopen($file, 'rb');
+ fseek($fp, $dataoffset, SEEK_SET);
+ $pos = $dataoffset + self::_endOfStubLength(fread($fp, 5));
+ fclose($fp);
+ self::_mapPhar($file, $pos);
+ } catch (Exception $e) {
+ die($e->getMessage());
+ }
+ }
+
+ /**
+ * Sub-function, allows recovery from errors
+ *
+ * @param unknown_type $file
+ * @param unknown_type $dataoffset
+ */
+ private static function _mapPhar($file, $dataoffset, $alias = NULL)
+ {
+ $file = realpath($file);
+ if (isset(self::$_manifest[$file])) {
+ return;
+ }
+ if (!is_array(self::$_pharMapping)) {
+ self::$_pharMapping = array();
+ }
+ $fp = fopen($file, 'rb');
+ // seek to __HALT_COMPILER_OFFSET__
+ fseek($fp, $dataoffset);
+ $manifest_length = unpack('Vlen', fread($fp, 4));
+ $manifest = '';
+ $last = '1';
+ while (strlen($last) && strlen($manifest) < $manifest_length['len']) {
+ $read = 8192;
+ if ($manifest_length['len'] - strlen($manifest) < 8192) {
+ $read = $manifest_length['len'] - strlen($manifest);
+ }
+ $last = fread($fp, $read);
+ $manifest .= $last;
+ }
+ if (strlen($manifest) < $manifest_length['len']) {
+ throw new Exception('ERROR: manifest length read was "' .
+ strlen($manifest) .'" should be "' .
+ $manifest_length['len'] . '"');
+ }
+ $info = self::_unserializeManifest($manifest);
+ if ($info['alias']) {
+ $alias = $info['alias'];
+ $explicit = true;
+ } else {
+ if (!isset($alias)) {
+ $alias = $file;
+ }
+ $explicit = false;
+ }
+ self::$_manifest[$file] = $info['manifest'];
+ $compressed = $info['compressed'];
+ self::$_fileStart[$file] = ftell($fp);
+ fclose($fp);
+ if ($compressed & 0x00001000) {
+ if (!function_exists('gzinflate')) {
+ throw new Exception('Error: zlib extension is not enabled - gzinflate() function needed' .
+ ' for compressed .phars');
+ }
+ }
+ if ($compressed & 0x00002000) {
+ if (!function_exists('bzdecompress')) {
+ throw new Exception('Error: bzip2 extension is not enabled - bzdecompress() function needed' .
+ ' for compressed .phars');
+ }
+ }
+ if (isset(self::$_pharMapping[$alias])) {
+ throw new Exception('ERROR: PHP_Archive::mapPhar has already been called for alias "' .
+ $alias . '" cannot re-alias to "' . $file . '"');
+ }
+ self::$_pharMapping[$alias] = array($file, $compressed, $dataoffset, $explicit,
+ $info['metadata']);
+ self::$_pharFiles[$file] = $alias;
+ }
+
+ /**
+ * extract the manifest into an internal array
+ *
+ * @param string $manifest
+ * @return false|array
+ */
+ private static function _unserializeManifest($manifest)
+ {
+ // retrieve the number of files in the manifest
+ $info = unpack('V', substr($manifest, 0, 4));
+ $apiver = substr($manifest, 4, 2);
+ $apiver = bin2hex($apiver);
+ $apiver_dots = hexdec($apiver[0]) . '.' . hexdec($apiver[1]) . '.' . hexdec($apiver[2]);
+ $majorcompat = hexdec($apiver[0]);
+ $calcapi = explode('.', self::APIVersion());
+ if ($calcapi[0] != $majorcompat) {
+ throw new Exception('Phar is incompatible API version ' . $apiver_dots . ', but ' .
+ 'PHP_Archive is API version '.self::APIVersion());
+ }
+ if ($calcapi[0] === '0') {
+ if (self::APIVersion() != $apiver_dots) {
+ throw new Exception('Phar is API version ' . $apiver_dots .
+ ', but PHP_Archive is API version '.self::APIVersion(), E_USER_ERROR);
+ }
+ }
+ $flags = unpack('V', substr($manifest, 6, 4));
+ $ret = array('compressed' => $flags & 0x00003000);
+ // signature is not verified by default in PHP_Archive, phar is better
+ $ret['hassignature'] = $flags & 0x00010000;
+ $aliaslen = unpack('V', substr($manifest, 10, 4));
+ if ($aliaslen) {
+ $ret['alias'] = substr($manifest, 14, $aliaslen[1]);
+ } else {
+ $ret['alias'] = false;
+ }
+ $manifest = substr($manifest, 14 + $aliaslen[1]);
+ $metadatalen = unpack('V', substr($manifest, 0, 4));
+ if ($metadatalen[1]) {
+ $ret['metadata'] = unserialize(substr($manifest, 4, $metadatalen[1]));
+ $manifest = substr($manifest, 4 + $metadatalen[1]);
+ } else {
+ $ret['metadata'] = null;
+ $manifest = substr($manifest, 4);
+ }
+ $offset = 0;
+ $start = 0;
+ for ($i = 0; $i < $info[1]; $i++) {
+ // length of the file name
+ $len = unpack('V', substr($manifest, $start, 4));
+ $start += 4;
+ // file name
+ $savepath = substr($manifest, $start, $len[1]);
+ $start += $len[1];
+ // retrieve manifest data:
+ // 0 = uncompressed file size
+ // 1 = timestamp of when file was added to phar
+ // 2 = compressed filesize
+ // 3 = crc32
+ // 4 = flags
+ // 5 = metadata length
+ $ret['manifest'][$savepath] = array_values(unpack('Va/Vb/Vc/Vd/Ve/Vf', substr($manifest, $start, 24)));
+ $ret['manifest'][$savepath][3] = sprintf('%u', $ret['manifest'][$savepath][3]);
+ if ($ret['manifest'][$savepath][5]) {
+ $ret['manifest'][$savepath][6] = unserialize(substr($manifest, $start + 24,
+ $ret['manifest'][$savepath][5]));
+ } else {
+ $ret['manifest'][$savepath][6] = null;
+ }
+ $ret['manifest'][$savepath][7] = $offset;
+ $offset += $ret['manifest'][$savepath][2];
+ $start += 24 + $ret['manifest'][$savepath][5];
+ }
+ return $ret;
+ }
+
+ /**
+ * @param string
+ */
+ private static function processFile($path)
+ {
+ if ($path == '.') {
+ return '';
+ }
+ $std = str_replace("\\", "/", $path);
+ while ($std != ($std = ereg_replace("[^\/:?]+/\.\./", "", $std))) ;
+ $std = str_replace("/./", "", $std);
+ if (strlen($std) > 1 && $std[0] == '/') {
+ $std = substr($std, 1);
+ }
+ if (strncmp($std, "./", 2) == 0) {
+ return substr($std, 2);
+ } else {
+ return $std;
+ }
+ }
+
+ /**
+ * Seek in the master archive to a matching file or directory
+ * @param string
+ */
+ protected function selectFile($path, $allowdirs = true)
+ {
+ $std = self::processFile($path);
+ if (isset(self::$_manifest[$this->_archiveName][$path])) {
+ $this->_setCurrentFile($path);
+ return true;
+ }
+ if (!$allowdirs) {
+ return 'Error: "' . $path . '" is not a file in phar "' . $this->_basename . '"';
+ }
+ foreach (self::$_manifest[$this->_archiveName] as $file => $info) {
+ if (empty($std) ||
+ //$std is a directory
+ strncmp($std.'/', $path, strlen($std)+1) == 0) {
+ $this->currentFilename = $this->internalFileLength = $this->currentStat = null;
+ return true;
+ }
+ }
+ return 'Error: "' . $path . '" not found in phar "' . $this->_basename . '"';
+ }
+
+ private function _setCurrentFile($path)
+ {
+ $this->currentStat = array(
+ 2 => 0100444, // file mode, readable by all, writeable by none
+ 4 => 0, // uid
+ 5 => 0, // gid
+ 7 => self::$_manifest[$this->_archiveName][$path][0], // size
+ 9 => self::$_manifest[$this->_archiveName][$path][1], // creation time
+ );
+ $this->currentFilename = $path;
+ $this->internalFileLength = self::$_manifest[$this->_archiveName][$path][2];
+ // seek to offset of file header within the .phar
+ if (is_resource(@$this->fp)) {
+ fseek($this->fp, self::$_fileStart[$this->_archiveName] + self::$_manifest[$this->_archiveName][$path][7]);
+ }
+ }
+
+ private static function _fileExists($archive, $path)
+ {
+ return isset(self::$_manifest[$archive]) &&
+ isset(self::$_manifest[$archive][$path]);
+ }
+
+ private static function _filesize($archive, $path)
+ {
+ return self::$_manifest[$archive][$path][0];
+ }
+
+ /**
+ * Seek to a file within the master archive, and extract its contents
+ * @param string
+ * @return array|string an array containing an error message string is returned
+ * upon error, otherwise the file contents are returned
+ */
+ public function extractFile($path)
+ {
+ $this->fp = @fopen($this->_archiveName, "rb");
+ if (!$this->fp) {
+ return array('Error: cannot open phar "' . $this->_archiveName . '"');
+ }
+ if (($e = $this->selectFile($path, false)) === true) {
+ $data = '';
+ $count = $this->internalFileLength;
+ while ($count) {
+ if ($count < 8192) {
+ $data .= @fread($this->fp, $count);
+ $count = 0;
+ } else {
+ $count -= 8192;
+ $data .= @fread($this->fp, 8192);
+ }
+ }
+ @fclose($this->fp);
+ if (self::$_manifest[$this->_archiveName][$path][4] & self::GZ) {
+ $data = gzinflate($data);
+ } elseif (self::$_manifest[$this->_archiveName][$path][4] & self::BZ2) {
+ $data = bzdecompress($data);
+ }
+ if (!isset(self::$_manifest[$this->_archiveName][$path]['ok'])) {
+ if (strlen($data) != $this->currentStat[7]) {
+ return array("Not valid internal .phar file (size error {$size} != " .
+ $this->currentStat[7] . ")");
+ }
+ if (self::$_manifest[$this->_archiveName][$path][3] != sprintf("%u", crc32($data))) {
+ return array("Not valid internal .phar file (checksum error)");
+ }
+ self::$_manifest[$this->_archiveName][$path]['ok'] = true;
+ }
+ return $data;
+ } else {
+ @fclose($this->fp);
+ return array($e);
+ }
+ }
+
+ /**
+ * Parse urls like phar:///fullpath/to/my.phar/file.txt
+ *
+ * @param string $file
+ * @return false|array
+ */
+ static protected function parseUrl($file)
+ {
+ if (substr($file, 0, 7) != 'phar://') {
+ return false;
+ }
+ $file = substr($file, 7);
+
+ $ret = array('scheme' => 'phar');
+ $pos_p = strpos($file, '.phar.php');
+ $pos_z = strpos($file, '.phar.gz');
+ $pos_b = strpos($file, '.phar.bz2');
+ if ($pos_p) {
+ if ($pos_z) {
+ return false;
+ }
+ $ret['host'] = substr($file, 0, $pos_p + strlen('.phar.php'));
+ $ret['path'] = substr($file, strlen($ret['host']));
+ } elseif ($pos_z) {
+ $ret['host'] = substr($file, 0, $pos_z + strlen('.phar.gz'));
+ $ret['path'] = substr($file, strlen($ret['host']));
+ } elseif ($pos_b) {
+ $ret['host'] = substr($file, 0, $pos_z + strlen('.phar.bz2'));
+ $ret['path'] = substr($file, strlen($ret['host']));
+ } elseif (($pos_p = strpos($file, ".phar")) !== false) {
+ $ret['host'] = substr($file, 0, $pos_p + strlen('.phar'));
+ $ret['path'] = substr($file, strlen($ret['host']));
+ } else {
+ return false;
+ }
+ if (!$ret['path']) {
+ $ret['path'] = '/';
+ }
+ return $ret;
+ }
+
+ /**
+ * Locate the .phar archive in the include_path and detect the file to open within
+ * the archive.
+ *
+ * Possible parameters are phar://pharname.phar/filename_within_phar.ext
+ * @param string a file within the archive
+ * @return string the filename within the .phar to retrieve
+ */
+ public function initializeStream($file)
+ {
+ $file = self::processFile($file);
+ $info = @parse_url($file);
+ if (!$info) {
+ $info = self::parseUrl($file);
+ }
+ if (!$info) {
+ return false;
+ }
+ if (!isset($info['host'])) {
+ // malformed internal file
+ return false;
+ }
+ if (!isset(self::$_pharFiles[$info['host']]) &&
+ !isset(self::$_pharMapping[$info['host']])) {
+ try {
+ self::loadPhar($info['host']);
+ // use alias from here out
+ $info['host'] = self::$_pharFiles[$info['host']];
+ } catch (Exception $e) {
+ return false;
+ }
+ }
+ if (!isset($info['path'])) {
+ return false;
+ } elseif (strlen($info['path']) > 1) {
+ $info['path'] = substr($info['path'], 1);
+ }
+ if (isset(self::$_pharMapping[$info['host']])) {
+ $this->_basename = $info['host'];
+ $this->_archiveName = self::$_pharMapping[$info['host']][0];
+ $this->_compressed = self::$_pharMapping[$info['host']][1];
+ } elseif (isset(self::$_pharFiles[$info['host']])) {
+ $this->_archiveName = $info['host'];
+ $this->_basename = self::$_pharFiles[$info['host']];
+ $this->_compressed = self::$_pharMapping[$this->_basename][1];
+ }
+ $file = $info['path'];
+ return $file;
+ }
+
+ /**
+ * Open the requested file - PHP streams API
+ *
+ * @param string $file String provided by the Stream wrapper
+ * @access private
+ */
+ public function stream_open($file)
+ {
+ return $this->_streamOpen($file);
+ }
+
+ /**
+ * @param string filename to opne, or directory name
+ * @param bool if true, a directory will be matched, otherwise only files
+ * will be matched
+ * @uses trigger_error()
+ * @return bool success of opening
+ * @access private
+ */
+ private function _streamOpen($file, $searchForDir = false)
+ {
+ $path = $this->initializeStream($file);
+ if (!$path) {
+ trigger_error('Error: Unknown phar in "' . $file . '"', E_USER_ERROR);
+ }
+ if (is_array($this->file = $this->extractFile($path))) {
+ trigger_error($this->file[0], E_USER_ERROR);
+ return false;
+ }
+ if ($path != $this->currentFilename) {
+ if (!$searchForDir) {
+ trigger_error("Cannot open '$file', is a directory", E_USER_ERROR);
+ return false;
+ } else {
+ $this->file = '';
+ return true;
+ }
+ }
+
+ if (!is_null($this->file) && $this->file !== false) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Read the data - PHP streams API
+ *
+ * @param int
+ * @access private
+ */
+ public function stream_read($count)
+ {
+ $ret = substr($this->file, $this->position, $count);
+ $this->position += strlen($ret);
+ return $ret;
+ }
+
+ /**
+ * Whether we've hit the end of the file - PHP streams API
+ * @access private
+ */
+ function stream_eof()
+ {
+ return $this->position >= $this->currentStat[7];
+ }
+
+ /**
+ * For seeking the stream - PHP streams API
+ * @param int
+ * @param SEEK_SET|SEEK_CUR|SEEK_END
+ * @access private
+ */
+ public function stream_seek($pos, $whence)
+ {
+ switch ($whence) {
+ case SEEK_SET:
+ if ($pos < 0) {
+ return false;
+ }
+ $this->position = $pos;
+ break;
+ case SEEK_CUR:
+ if ($pos + $this->currentStat[7] < 0) {
+ return false;
+ }
+ $this->position += $pos;
+ break;
+ case SEEK_END:
+ if ($pos + $this->currentStat[7] < 0) {
+ return false;
+ }
+ $this->position = $pos + $this->currentStat[7];
+ default:
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * The current position in the stream - PHP streams API
+ * @access private
+ */
+ public function stream_tell()
+ {
+ return $this->position;
+ }
+
+ /**
+ * The result of an fstat call, returns mod time from creation, and file size -
+ * PHP streams API
+ * @uses _stream_stat()
+ * @access private
+ */
+ public function stream_stat()
+ {
+ return $this->_stream_stat();
+ }
+
+ /**
+ * Retrieve statistics on a file or directory within the .phar
+ * @param string file/directory to stat
+ * @access private
+ */
+ public function _stream_stat($file = null)
+ {
+ $std = $file ? self::processFile($file) : $this->currentFilename;
+ if ($file) {
+ if (isset(self::$_manifest[$this->_archiveName][$file])) {
+ $this->_setCurrentFile($file);
+ $isdir = false;
+ } else {
+ do {
+ $isdir = false;
+ if ($file == '/') {
+ break;
+ }
+ foreach (self::$_manifest[$this->_archiveName] as $path => $info) {
+ if (strpos($path, $file) === 0) {
+ if (strlen($path) > strlen($file) &&
+ $path[strlen($file)] == '/') {
+ break 2;
+ }
+ }
+ }
+ // no files exist and no directories match this string
+ return false;
+ } while (false);
+ $isdir = true;
+ }
+ } else {
+ $isdir = false; // open streams must be files
+ }
+ $mode = $isdir ? 0040444 : 0100444;
+ // 040000 = dir, 010000 = file
+ // everything is readable, nothing is writeable
+ return array(
+ 0, 0, $mode, 0, 0, 0, 0, 0, 0, 0, 0, 0, // non-associative indices
+ 'dev' => 0, 'ino' => 0,
+ 'mode' => $mode,
+ 'nlink' => 0, 'uid' => 0, 'gid' => 0, 'rdev' => 0, 'blksize' => 0, 'blocks' => 0,
+ 'size' => $this->currentStat[7],
+ 'atime' => $this->currentStat[9],
+ 'mtime' => $this->currentStat[9],
+ 'ctime' => $this->currentStat[9],
+ );
+ }
+
+ /**
+ * Stat a closed file or directory - PHP streams API
+ * @param string
+ * @param int
+ * @access private
+ */
+ public function url_stat($url, $flags)
+ {
+ $path = $this->initializeStream($url);
+ return $this->_stream_stat($path);
+ }
+
+ /**
+ * Open a directory in the .phar for reading - PHP streams API
+ * @param string directory name
+ * @access private
+ */
+ public function dir_opendir($path)
+ {
+ $info = @parse_url($path);
+ if (!$info) {
+ $info = self::parseUrl($path);
+ if (!$info) {
+ trigger_error('Error: "' . $path . '" is a file, and cannot be opened with opendir',
+ E_USER_ERROR);
+ return false;
+ }
+ }
+ $path = !empty($info['path']) ?
+ $info['host'] . $info['path'] : $info['host'] . '/';
+ $path = $this->initializeStream('phar://' . $path);
+ if (isset(self::$_manifest[$this->_archiveName][$path])) {
+ trigger_error('Error: "' . $path . '" is a file, and cannot be opened with opendir',
+ E_USER_ERROR);
+ return false;
+ }
+ if ($path == false) {
+ trigger_error('Error: Unknown phar in "' . $file . '"', E_USER_ERROR);
+ return false;
+ }
+ $this->fp = @fopen($this->_archiveName, "rb");
+ if (!$this->fp) {
+ trigger_error('Error: cannot open phar "' . $this->_archiveName . '"');
+ return false;
+ }
+ $this->_dirFiles = array();
+ foreach (self::$_manifest[$this->_archiveName] as $file => $info) {
+ if ($path == '/') {
+ if (strpos($file, '/')) {
+ $a = explode('/', $file);
+ $this->_dirFiles[array_shift($a)] = true;
+ } else {
+ $this->_dirFiles[$file] = true;
+ }
+ } elseif (strpos($file, $path) === 0) {
+ $fname = substr($file, strlen($path) + 1);
+ if (strpos($fname, '/')) {
+ // this is a directory
+ $a = explode('/', $fname);
+ $this->_dirFiles[array_shift($a)] = true;
+ } elseif ($file[strlen($path)] == '/') {
+ // this is a file
+ $this->_dirFiles[$fname] = true;
+ }
+ }
+ }
+ @fclose($this->fp);
+ if (!count($this->_dirFiles)) {
+ return false;
+ }
+ @uksort($this->_dirFiles, 'strnatcmp');
+ return true;
+ }
+
+ /**
+ * Read the next directory entry - PHP streams API
+ * @access private
+ */
+ public function dir_readdir()
+ {
+ $ret = key($this->_dirFiles);
+ @next($this->_dirFiles);
+ if (!$ret) {
+ return false;
+ }
+ return $ret;
+ }
+
+ /**
+ * Close a directory handle opened with opendir() - PHP streams API
+ * @access private
+ */
+ public function dir_closedir()
+ {
+ $this->_dirFiles = array();
+ reset($this->_dirFiles);
+ return true;
+ }
+
+ /**
+ * Rewind to the first directory entry - PHP streams API
+ * @access private
+ */
+ public function dir_rewinddir()
+ {
+ reset($this->_dirFiles);
+ return true;
+ }
+
+ /**
+ * API version of this class
+ * @return string
+ */
+ public final function APIVersion()
+ {
+ return '1.1.0';
+ }
+
+ /**
+ * Retrieve Phar-specific metadata for a Phar archive
+ *
+ * @param string $phar full path to Phar archive, or alias
+ * @return null|mixed The value that was serialized for the Phar
+ * archive's metadata
+ * @throws Exception
+ */
+ public static function getPharMetadata($phar)
+ {
+ if (isset(self::$_pharFiles[$phar])) {
+ $phar = self::$_pharFiles[$phar];
+ }
+ if (!isset(self::$_pharMapping[$phar])) {
+ throw new Exception('Unknown Phar archive: "' . $phar . '"');
+ }
+ return self::$_pharMapping[$phar][4];
+ }
+
+ /**
+ * Retrieve File-specific metadata for a Phar archive file
+ *
+ * @param string $phar full path to Phar archive, or alias
+ * @param string $file relative path to file within Phar archive
+ * @return null|mixed The value that was serialized for the Phar
+ * archive's metadata
+ * @throws Exception
+ */
+ public static function getFileMetadata($phar, $file)
+ {
+ if (!isset(self::$_pharFiles[$phar])) {
+ if (!isset(self::$_pharMapping[$phar])) {
+ throw new Exception('Unknown Phar archive: "' . $phar . '"');
+ }
+ $phar = self::$_pharMapping[$phar][0];
+ }
+ if (!isset(self::$_manifest[$phar])) {
+ throw new Exception('Unknown Phar: "' . $phar . '"');
+ }
+ $file = self::processFile($file);
+ if (!isset(self::$_manifest[$phar][$file])) {
+ throw new Exception('Unknown file "' . $file . '" within Phar "'. $phar . '"');
+ }
+ return self::$_manifest[$phar][$file][6];
+ }
+
+ /**
+ * @return list of supported signature algorithmns.
+ */
+ public static function getsupportedsignatures()
+ {
+ $ret = array('MD5', 'SHA-1');
+ if (extension_loaded('hash')) {
+ $ret[] = 'SHA-256';
+ $ret[] = 'SHA-512';
+ }
+ return $ret;
+ }
+}
+?><?php
+}
+if (!in_array('phar', stream_get_wrappers())) {
+ stream_wrapper_register('phar', 'PHP_Archive');
+}
+if (!class_exists('Phar',0)) {
+ include 'phar://'.__FILE__.'/phar.inc';
+}
+?><?php
+
+/** @file phar.php
+ * @ingroup Phar
+ * @brief class CLICommand
+ * @author Marcus Boerger
+ * @date 2007 - 2007
+ *
+ * Phar Command
+ */
+
+if (!extension_loaded('phar'))
+{
+ if (!class_exists('PHP_Archive', 0))
+ {
+ echo "Neither Extension Phar nor class PHP_Archive are available.\n";
+ exit(1);
+ }
+ if (!in_array('phar', stream_get_wrappers()))
+ {
+ stream_wrapper_register('phar', 'PHP_Archive');
+ }
+ if (!class_exists('Phar',0)) {
+ require 'phar://'.__FILE__.'/phar.inc';
+ }
+}
+
+foreach(array("SPL", "Reflection") as $ext)
+{
+ if (!extension_loaded($ext))
+ {
+ echo "$argv[0] requires PHP extension $ext.\n";
+ exit(1);
+ }
+}
+
+function command_include($file)
+{
+ $file = 'phar://' . __FILE__ . '/' . $file;
+ if (file_exists($file)) {
+ include($file);
+ }
+}
+
+function command_autoload($classname)
+{
+ command_include(strtolower($classname) . '.inc');
+}
+
+Phar::mapPhar();
+
+spl_autoload_register('command_autoload');
+
+new PharCommand($argc, $argv);
+
+__HALT_COMPILER(); ?>\r
+6\ 1\0\0\ 6\0\0\0\11\0\0\0\ 1\0\v\0\0\0pharcommand\0\0\0\0\ e\0\0\0clicommand.inc>,\0\0\89í[F¤
+\0\0+ó©P¶\11\0\0\0\0\0\0\1a\0\0\0directorygraphiterator.incô\ 2\0\0\89í[Fu\ 1\0\0ôÎr\86¶\11\0\0\0\0\0\0\19\0\0\0directorytreeiterator.inc%\ 5\0\0\89í[F]\ 2\0\0\17\86p\8b¶\11\0\0\0\0\0\0\19\0\0\0invertedregexiterator.incÖ\ 1\0\0\89í[FÕ\0\0\0ICÖC¶\11\0\0\0\0\0\0\ f\0\0\0pharcommand.incy£\0\0\89í[FÍ\1f\0\0\15\ fä\ 6¶\11\0\0\0\0\0\0\b\0\0\0phar.inc\16\ 3\0\0\89í[F)\ 1\0\0ìk\ 6<¶\11\0\0\0\0\0\0Å\1akoÛFò»\7fÅZÐ\95T,É\96] wv¤^.w\ 5
+$m\90¤\9f\14A ©¥Ä\vEê\96¤íÀõ\7fïÌ>È]î\92\94{Æ\1d\81Ä\12wvÞ;¯Õë\1f\ f»ÃÉÉù«WäïQ\9cP\12&q\98í÷Aº\99ÆixBà}\9cnYV\1eÈ\87]Àø\8b[\16Ó\b \83<'oßýüVÀó¥ ,v\19#ä}ÀÂ2'ÿÈ(ÛR±k\13\14\94Àsyqñ\ 3\99ð?ð\1e\97\101©±\9cK~Zè\12òæ6/X\10\16ä6È\81ã,Í3ä\ ñþ\90Ð=M\8b \88³´\8f«;Êr\0#³é\ 5'\1d(Ü\96x\8f'Èý\81e\ 5\r\vº!Ã\80mÃ\eÇË;ëe¸ßädN\ 2Æ\82oþȵ§k¹øv0\96ùzT¦!ÊGÖkT@Áʰð9Kc\ 1)X\19q`Á:>Ãb\17ç\93\ 5Â\ 1JM\ 4sñN.ÞY\8bR\94\9c&Ñõõ\96\16R;¹Ï×G\16¼d¾\82\7fö\9fáU\ 5^ÁÇ\11\11ü\93×är¤±\8c\8fØN\19Ë\98?ø%«l½\8dïh:&á\8e\86_Éð\119^^¬\9eÈ\8e&\87/é@cç\89Ð$§Hä4ÎsZø\9a<K.êr¶Z-=V¦ÞjÔIÿ·ôk\9aݧ\15\13\9e$<[=yÏà¥Ab¨ÐIÍ\ 3:m\87©'\87\ 4r7H\0\9b\1d\12Ô¶Es\84A\92¬Ë\9c²5ú\91/\\8b\83\8cI7Ú\e\13k\fÈf\8dw{`\ fÎ.¬D\ 1Èi®Þï0Êøgg°õµpÀ&«º7Ü-\87ñ
+ÔHæsâM<\17¨\ 2\873\90дÞ5Â=\97ä»ï\88¡.ÔÀ²F\rF·teH\ 3\90\95IÄ\86\9bV`d\83K¶\98·\8b¦?\86_½\97z\83\8d%Æ/Rdä\10°`O\vÊÀËÐ\ 2$\8b4¿\93\9f\8eóºæãôBKü\86ÒÀ\11î\82Ä[¡J¤\9f eqª¹îÁ\81â1\91\91HÄ \ e\1e\9c+O¤\8f5çyÔuõ¨ìõä¡\1a\95Ê\94Æ\9e0\9bÑNõÝ2\1a|µ1\99XÌoÖ¹æ:÷\1cGYA\1fágH!ÐÑÿ\941£\80\1f\8fH×ò\91fPQP&à½,\88\13Ý\9fóÿ\87%,Á\94û\1aÙ¶ùð(åw\87¨n
+Ë\95\165ÎÎZ\82\86C\18ÓE\84hÒÚ\1dÌ4\ e\ 4}8\88âA\19ãel`2g|\892pùp§û\19 r\19>\17\10\13Ò¨Í\8fµÀÍ}Q%hØ"\959Ò¢8\7f+½s£¼×zÙâ\f*5Mç\84T\ e«Å\8d\89\b²ÏÒÑó\8f¹\12Xr3\1a\19\10ÝÆ6µYF+\15þD\96\17åÏXwjIIâͱ¬\ eëò3Íà+$ôá>ß6\8bÍèÀâ´\88üO\9fÿù¯\8f\1f\ 1)Âtbã2
+d\0N\1fâ\ 2ªÛ\rÅ"cD\1aØ\ 5e_C\8a\ fîñë\9d&¹\8aÎ\11IË*\9c¿\1dꤧçCXðV7\1d\ 5\1a\96ÀKܯ\80\88ÎhQ²ô\18{Ù¸Æum2¶Ù\13«}µ§¤_!Ò\vÏ\ ekA9ÿ©¼ý ¾æ~Ý(ñv\87wO@üÀh\14?T-I^Þæ\96f\ 3W4\1e2x\9bÒ{ò\91F åôÞ"N¿Â®\ 3'ØbÈS%HêE\15\9bØd\ 1<¿§Ð\rBÇ2â\ 1j_\9f¾Gû¤\96Ø\ e\82\8fM\16)Ä\881¹\0\99\12^Y*:=g·¢\8d¨8Aø0²ÀZâÕý.(P´&\eÃäL\89\8bèÎf-yl\88¶"\15³dÊÉÃ\1foíá\17Äß²S\91.Ø\9aÑC\12ÀQ\83Mc¬ÂÇbµ\85&OV é]\90\vMû\9c\8b\91-t»à
+\8fJ\ 5Á\92S\µ éFÄÅQ\18ú2?>îªÔ@³D="²óWh\151,\0µ^_\83^_\9d\vÅÿÉ\9c\7fb\7fª\ ehgôÔÛq×yl\9e<\89µêͫì\9d`/Lâ5|EÓ\vÅñNpìAÊ\85ÿ1_\8cºcºÖô¿(SÀ\86Æ\14\ 6Ã\1eFÔ&\0]ßfY¢"\7f\18áÿ_é·\16V|\ 4\1e!°\81¾\97\ 6ä>\9bD3\8b¡\97û\0Éñ\93SQ3v\8e\1fÞhíá\ 4q\92}\99\17ä\96\92 %\80\89n)\9b6\ 6\ e'\96L\8a¤\12é(\89\18à~èU[³¦ë\f°zí· 3^ÍÁ\17Ùòó\8f:Ìd¶B\10xuÈrß;\1f{2Ã\81ê伡/"kÉ®«ºÅ4y\1c&ï\9cÇR´ß\14¿´WfNÜÎTüËoïÞ\1d\99\85u\ 3\81£ÐÐáu\ e\v\9dÆéZV\18\1c\9a\7f^\ 30\9e´h»ô\ 4.¬V:ÝñCU=C©^R5§\80ê\8cd)Åy\857\0½ü;\8bS\7f\80ùcÐI\v@\a\9eå¾¶;B'\9b\98õ*d\18A(\87D\9d\1c\82bçË\92ÉP×0\9aÏçÜ¿Èï¿\93S\9c\95¯¡ÊÌ\v\10\ 1:\e|\17ç\82VÔ°\8fЦÐ\1c\9b3$¦ôµÉhÎ\95Æ\91ö* :Zü\88w²(\91Kf¬°>\1d\92\9f\0èç4ÊüFµÈa\86\11/\9b>\82z> z´õ~Í´\1d~\1aî2¢é\82_>´êÂ<R¼Æ\9f½ ~@\vý.\82\93Y°/\16`N5Õî³Ñ\96\1aª\82 ¦ÂT÷¡\ 2Ï\80Ò±G-Ý*\80£¤
+G.\9b\8a£\eÈ\93ÏRO\98¹2\99;Yró\83·àD\81\ 3\a_\bætI\ 3_[«\ 6\e\11ß§\ f\97þ0\99\89p¿ÆqBKá
+V\1a\14¾G0;$3rF.áß÷ðﯽT®$\95äò¿%%?\ 3&üÔ_\9b`\95\ 5ÄÖ8Wð[H\ e>C\83Ç'\ f\ 4¼\83ÿE7 \88\88 p\90ÔíÝÀ \a\9dø\1dÞ¿\19\ 4ï3¶¹g\ 1´ÀXÓ"ÿð/?X\9e\8f\8dï>xð\7fø\e\99p ï/F7|éü\9cìã4Þ\97{\ 2®µ\95N\8b\ 3\95-àÝÕ(nµ.F\10\13\9dÔ\r¢\80·1ÈS\16P¾ÄE\1c$°b6\82æV¾OPgt\1fÄé\ 6/ó\fxk\19ÀA\19\13ü\7f
+ÂÁn&¨Æi½\9bH`ò%õrë$aÃTë\8aa[[#\1cõë\19ÍĽ\vûrÑ\rUÊF~äÜÊÒ;8\ 3È2Т\9fê&\e\93\ 2\13åÈ\18¼Á9\8cº*05«@8{°f¿Å\12ÕäØ\8d\e\1f\8c\ 1qZ6®\80Ú\abfµèÆ)/d\ 6|TGÈ \v÷\115\9cB7\9dN»q\81b/µ[\ f#*\8dÅ|³q\ f\ 6ç^\eKÀvëò\fì;5PÖ^\96\1fê\9aRZ\ 1;®\95\8aL\88\ ek%+9jã'±ªÐ aV¦öJ¯Î\13¼4¼°ûÙjºa"ä\ e\98\1d
+î\80|T`íl\19xpB\18kàS\9d±\0UóæÑ6\904Ò\95ËHWÂH\88Óa)AùÊ´Ö\95\ 3èÅÅíö\80K40¸8&r9J\1düe2|Lò§\1c^\8f9Ñ\91\9aã |WÜ3®Ü\9ea«ÌÕ\9bèç\11UÕ\15;\8e\ e\ 4*\92r¯æU\1fîªo%®¿¤À.J\ 2$_¦+\93´~=`\18\86\94Ò ÕMÊh¸¬$\8dUAW\92\96# \ fýA\eOÌ\17^\90~óÆüNc¾À\16O\8cQ`¡bSÝ;@s\ fØXLïh\95æ§Í \87Å\19+S7g|´K\8c\ 1¶þÛ\8eû]\1cî\1aãíú.ˬ÷epá[:½CÆ\1a\ 1\88ycÖ{sõ\1e\ e\18)vAÊ{GãW\1eÓg]GÕ\12ñ\ fË\8b\95\1d%O«6´êW8°q9â¼}íú9È\98\84A\8aUºa>'÷\8dt¡\85\1f¡³Fº0~E¤\ 4\\9879üíªoÞ/\9a¯/éPÞe\91×\92ù\ 5YfÜ\13ó\15?%Í\8cfg\81¯yÆ\8c\9f¢4¸nÜ\vr\190\b\eŹG\1fÎ]JæÔD*¨3\ 1nk¦\82F\9e\96U\93\9a\84^[BäE£ª\92Û6\9a\ 1øuåYó§-G
+Ó\9fM\v\8cúÐ3`ÄÃÍ\9d!\ f\8dåÌ\10Àä\14\91ñ¤¶\19Ûý\b¼\1dÉ\`\eSº\93&\8b«\9bÄ0:wt:ZKch¦W'\8f.k èº_ź¸ËäZ\1câèeqÔ_Èt$ÜÎÛ7\93\8aVj·%Z\9bCù\ 3ªg\96\ 6nì-²\98\8d\86S\ 2Á\85Ö~\14¬¤-w!ÿ3\1eÄ@äøj\ 5\1f\11Ã\90\81\86skcV\9c\13]<¯ñ^'\90 Z»ïw\98&Hp\17ÄIp[ÿæ4otÛyÙ\8d½+\86Êpåy\8e³ö¬\90ª¢\8e:jp\8e\9d:CµªcÈc\v4ê\93\99éèO' è\8f\8b\93?\0\85RÑNÂ0\14}fÉþá>ø \ 6\ 15¾L#â\98°8\90°½ø´ÔîÂ\9a`·´\9dBÔ\7f·ÝØDc°\ f»Ý=ç\9e\9eÓôz\90§¹mÙVïä\ 4n\97l\8d\900\81Teb»\12$O\99BAô_\97qj[ I\8c¯DVäàmÈK¾FYu\9f\ 5Ã%Ð5\91\12FµÂØ(ø;\85\8aG
+\95f\ 2`J\ 4-$Üe(V¸Ã\12¢\10ô:ï÷/àÔ\94K\ 3\94`8\ ft+T\84'D$0\9fÌ!`Ï\82\88\81{M\84Cî\0\86 \ 4"Ô¡@¥DAÆ×[\90iö&\9bì\fe÷\7f¿¯($Ë8\9cuÏv&\ eå\aÜ(äÉ\1e\1ci/ß·ón[eÁ©2\92qL3.\95(¨:>Ê\89JÛ\1a5\8cÖ\ 2i¡\8f}m&ëê8ûC\86Úâø\ 6\rß%4Õ·SÓ+FI\99\13\81\ý\ 2~\ e7\9e\eVéªs\80á8\ fÞS<\fã{?ðfé·ÓmWµÝ\81jóË\97ã¸Ã \88£Ç0Zø³ñÇ\1fpäNâ±\17ÅîÄ\ fF¥H-\96\97I\1c'ô\82{}î"\8cL»}¥¿\9f¶õi^Éàæ\v\8dSÛnÚ@\10}\ 6\89\7f\98\a$ì\ 4\biÕ\17'!¡@\12T'\8db^*U²\163Ø+\19Û\9a]' &ÿÞYÛ\r\11%Öx.gÎ\1c\1f\9f_fQÖ¨7ê'GGpµ\901Â\\12\ 6:¥µ&D©\91\ 4?te\124êÀ52 )Í3\18¯Ä2\8bQ\95Ñ\19I\@\10\v¥`´\ 1\982À¤\ 2(ËD®£\94\0î\ 4\ 5¹\82ï)R\88Un.4\ 2__z½¯Ð1·o&Q$½\a\97C\9e\16É\Ð\1c\1en\1fÀ\953\12´6é\93í\ 2\87ÈÁ\8eØ\86\14è\14BLÌ\ 3ÂÀ\eN&\10\92È"\19ìT\0#\83ú7ý'$%Ó\ 4N»§\15§\ 3j\0®4&s\ 5\8f\18äÜ÷´ÍìôúÓ¨×ÌRÃ4Q\9aò@Ã\82Ò%\bÈ\84\8eº\9c4S3Ab M\13Ú§\9cBùâ°(c.µE\9e\ 4Úðóý`\ 3h\15}6gͬ\1aca¢\1dg¿ÂÄk >ï\88\ eE\10±Ì\e\9eeÅÛ\92\ f:\97\83Ú\a*\1cçÇø\97?ðüë\89;¾\1fÜ\8dKX»\rå\9fwS\1dg8p]\7fúÓ\9b>Nîo^>IO\87·þÍxê\ fo'î¨\0Ù\80möôÆî5Ï{ô¦&l\9fñùj\9cT¨~E¨sJ@G\bLÚt\0Ƹ4÷\8cp!W8\87gɲ¿ñ\8d*\ 5¯í+^µ[[¡\9bÆRp\ 1\96\99Y[°\1f¬f|Ñ;\83f\fçÐÔ\91T\9d~\88z\84\99\8e,ÛÄ\8f\8fm(\9a«îîÅ^\9d\97ÏvRÇv§\1f uÏ\16³l¸\84Ö\v´Àá\1f\94ã^ÍQmWañøÿÅê\14X¿;-»\10\13Ê«{\88\8cïëÔÓÄïÇz'ò \f C¶©*t\96 \7f\8a ·_À\a%Ù\99"\8e¦ ´\8dëÙüj+kµ\93)ñs\85ä\9b2_\10\89µU\9e\9f\93d_\14\88ö\ e²¢Y0½ìÿ\ 5\85PÍj\ 21\10>o ï0ÞªPÝz\11VÑÒ\9b\a¡ô\rbvv7 É2\99\14A|w\93u[ZÅu.\ 3óý&«MÛ´RH1\9bLà½2\a\ 4c¿\91\18KÂ\1a\8f\86\91\14;\9a\1a«¥\80È1¶&\17Zøl\14]/{2X\81>(ïaÛ\8b¿\92xÛ\8b¯4\15¸q\ 4°S¤\83\87\ f\87Tc\8f\95\8a\11âÌó|\ 1¯ÝJ@\aþXÂ\9dçì·ø£R0 \1en\14UÞ8\voÓ¼\8f\1ax à\91Ñ\96þ6ä$EÖõ#ä@\16Fÿð¢PZcË/ãH\8b\11Y\U°\9aSî\1f(¹dO\1c\96\91s\96â\9c~d³¾\0í=ýwÛ6\92?'\7f\ 5\92sK¹\91e;{½{\97Ôn\9dÔMó^\92æÅéõm\9d¬\97\96 \89g\8aÔ\92Tb·\9bÿýf\ 6\1f\ 4@\80¤$§»{ïü^\eI\ 4\ 6\83Á|af\0~óír¾¼{wÿ«¯î²¯ØwÓ$ål9\8f\8bq¾XÄÙd\94dcz\90d³"_-ÙkxF?\\16 \9f²q\1a\97%{úâùSÑ\9e\1eÅ«j\9e\17\8c½\ 40«\92=Éy1ã¢×$®8\83¿\87\a\aÿÉöè\1fø\1d\1f!`VCÙ¿»¿Ï~ÿýw9\ 2>\95\ f\19¿®x6±F\95è\9b¨\1fþ\88ÿ½\9d'¥\844\87\87)/Y5çâ3Ì\8cåSú¾\94\93\93\93/GìyÅ>&iÊ.9[\95|¦E¾P\8f\19tåûã<+ó\94c·$cy1á\ 5«rVð
+\bô\813\811\1f¯*\ 1\9fMWÙ¸J ×Ha\17".\13D\91#èa\93Å2å\v\9eU1\82颸\a^\94Ð\8c\1d\8e\ e\88¬½èùû]\$¹\ 2ËÕe\9a\8c5Þ@ÇäbÆ«\8b³×\ f©YËóÁNz8d;q1»H²é.5\17°ñ\ fh´*2VVÅEÁ\97<®\ 6\11\8b yzÈ\1e°\87ðß¿Ã\7fÿµû\98:|R(}úô©\1fv\7f\12Í\905ðï+ö4MØ3^1õ\88é'ß-ã"^ &È\r\88\0ý\9d¦°\82Y¨ÑCÑèíG\9e~à\81FræL?®ç\8cÏ\8119\13s\aæ\12?\8edÛ}ú×7/IÕôᶤ\95\9fq*ð©\83Ð%ò\9bAhdæ\v\18¾tÉLL\v\ fVÈ£¥úUýK¢XÏ*\a6N²\92Å dJ\ 4µüùWI\13÷ã<\19ÏñÑ/ôA\rÉPÖçyɳQ¨'\8eRÝ,9Ñ\9f>\80\ 6À\1f\87¬\òq2Å\89¢*\ 4Iþ\98\17W,ÏÜ\15\eWYþ1³\16+H¢\81ÀuX\8fì.Ø\8enË\8e`&E|3ÐÏð/\8a#vtì{BO\ 1$=\8fâ4\89ËhØlñ!N©Å«\9f_¼ð<\ 6\1e\12\0¾!\bÇ {\8aüC2A\ 5Æè'\96Å\vΦ fô:!\89F\91\ 5l×\86\1d\8dû¡\r+¾\8cÓÙ\96\88ÏrÀ\e\8dȲà%i=üHªùbä\ 3]ò\94\8f«6\f©ÙA\84ÿà\18¯räM\ 5Ý\ 3\92ÚgyÆ£5Ú\83öÎEû\13ø´@\1e\ 2q¸a\ 2=\13B=\9f¨\ 1j·u\1dx¿u\0ñ)n¶Z\ 5\82\0Ëð
+¹\ 5¤\8a¾\erÄ\ 6\8bU 2\9a\8dÓ\15p×ë\1fOÞÀ\97\8a\17Y\9c²IRÀ\8csè@Ì\96L\81ûnv;XlÚkjZò¶\99\1c2<²Ø\99P\12Ò\8dв`L³\ 3çy¿å\90\fº\rÊ\v\ e®Áä\98\9d\11(å÷\94ó\9a\95²~²\11-&_\v\98/¿ÿ:\1aFå<>\14ßÏ~<9\8cÚÙ/é7ß\82ÏøõVÓ%\bÇæ
+Å`\fg«\14\96\88_k9B5\96dËUEëVv¬ÖUOÝ\9bm':I6\11¸¯.Ëq\91,É\86Ð\8f\16c\r[qMûá
+"×\86ëA+¢è\16¥(ã«Å%¸»h;An9\9f q-W\97J\8cI@r²ºKá:\93\94 J\80G\1d\13Yü1D\aù\88Q¤_¿\f¶'±À8/8xþÕ\ê¯AÉ\8b\ 4Ìàoà¦Á\86\89\1avé¥e¿ ¤y\f{\86æ @\1c³\17ù\98ö\ 4¸"¯\7f|}qR\8cç ìA\84ÏO´\1f\803XÀÎ¥¬ö\88óÍvî\84¬¿Qôç|ÅÆà\rÀF\88½\8b\ eÞE°Û\81\ f\87ð\ 1H\96âØ ²+\16[FlU"S ÖAß\f\90\ 3
+¶\ eC\bªí'¸v<\930Ä\98\bIí\84&9L Ë+Æ\8b\ 2pÉA\9c?b{lÓ:\86A\10\98\11B\80\r\9e\98\ 1\8cI.j «\8fNeZæ,\9eÀö¨Ì\1782zD°Y\83Ñ;G)«Õ%t\83\86q¥ö±Æª\807_¢n\82µà\ 5P\ 5\,´$\8fÀß\ 6\89áà¯~,âå\12\ 4¬u\140\92\19\b_YÆÅÍ\88\9d\0bÓ$#ÒWÆ<h\17\vó ¬õ.\1f·÷B0[\87 @Ëx|\15ÏÄ\86\16\19\ e\97\1aÖ\9dgåªàÆ6\1dÝoÔ³°ÚmüÔ.üe?ÙÁ\89l%9¸DdÐ\85«\85Ä¡UëáÙ^ÿÑ&íM§\19£õ¸&Ǫ\89¼þ\ eû<ý\19\98g@û\7f\ 4wAzd2\88~K\93Ëhwר\9eà_½E9\a·þý¹r\11àÓì·è=69bѳ_A×\9bNïãþ@\92%\82i\aò©\vùËß\1e®\85;¶\7f/p\7f\ 2Ã>Ü\fùK@\1eát@1°ßA/ì"þ\10')ôBÉyô\bTÂÙj¹Ì\vÐCgÉ,\8ba«ÉËÁîckÎIv!]2ð¼ö\1e~ý\1f¸³¯¡µN~n£\rN\1cö'¼\ 1\18~\ e\92Ú\1eöëÃ\870l;Úkb\82 \15&øÙO6k\8flò2\b\ 3\8fÇó\81±\95\ 6\95º\93^ñ\eÚ\0\8c§³\ 6>+|(8\17tn\95¯Pß\ e¨Ï®³ö\ 5ÿÛ*A=MM\97¹±©G(»ìÞÑ\11\9b\82½àNÇ\9c\1c¹8õtLÝ\8eVO$z=ìßÿ^\83rç¡ sN \91\888ÝÇ\8dÎ#\ 5\9b¨®G²{}ºÛü$C \ 4l½ \11\10à4\9b\94¿\80gå\86\8dÎDl\ 6\1f3ýÜ\b\1cý\ 2\e\19°\85±
+âp°Cä¡Å`¿ñI\ 6\ e(hm\7fÐHE~æñ\rà4¾\12¡7õ-ÐX@ÄGØØ\86¯\ 3A\8bä\1a\ 3ø~¸bè\93dQe¢w\ 3ö3\9b\r¥u!Ð
+\88ý\a®3<\8f\0\25[Sx\96\80U\r<ü\91'\83Î\ 3=ç¡\9aQ(ZHÃ\9bí÷à{ʳ\81ê·Ë\80Uå\97õ\16\1eÃ\97\18«\ 4»(4uá®ÿ\89
+ßQ<Îh\13\K\80\a?\9f&´ú"\8a2d\91\92\11rOÁ]EËHÑ\ 4rÃü\84\97\7f:\1aÙpÖ\1c\f4
+ d\18pʦÉlU\bß\elð\12{ÿ1¬ÕGB Ô\9fÔ\ f2\17~p9Ë\9a'6R\11Îöµo\92z\80 \86\84í\90Æt\19\05\r5ÂõÅx\17*\eõ\15ööìË/Ù=\9cÇ\ 5¿\ 6wµ¤¶Mí>%¿ø\88\\1a[\8b(Ý\.Ó¤\1aÜ\7f\97Ý\1f²¿¶lEþºKº\eæêUu°½\18Ïyé\1dJÍ\a¬ïì\82\1a\ eî\ fÿ\ 2\9b¶sö®zÿ`pþ\17üwô\15\8e~þ\ eþößÃÀò\93\1c~\ 4Íww\86\80$¢0Ô\ 36¦Ü\98ºjy~ø¾\89\16þ]\ 2!®\9a\8f>Ý\r\7fÃÙÜKÊ\92W\ 31N\ 3\8d;;\8b\12\16\8bÝ\7f\8d$U\9eº¹Ù\0Y0æfî\bq÷CPG°*6bwÈ\ 2ÕlÑ\18ö\ eØïé£G\0"\19ó\ 1"áXÍ;\9f\18GÅèïGÛ6\7f·\16r\b\84$ÉM\1fA}RâCc\98Ò\80ó\15¬»¹òBç\ 2¤º]{¡Ø\8bd"=\rI¿\16lÕ\9e¼FØ"×"þ\ fÖ8\bMçUhSÔ[õHBuê\1e¹\9cþÕò\ 2°½á{Â\aMÊÿ\8eÓd\82_~\90\1a߯¥LÖ»ÿZ\85nKFaéyüAn\8fõÆ\82E#\9c
+\9a\16ú\80òS\7fÁÝ\ 3
+WDß`\1f\84R´ÛÂ\95\88ÓvܧW7È~¤¤q!õô\gê\8d@FÚFÆs\8c´Ûý\ 2\8e\94c}\99à\13"Y\92ÕápàÅ|Ù\92\81#6V½Ç\16;ÃÎ7/\162¹ÝÂĪ7~1ú4\1c43éGx\12cËô\ 4",v\8e5±j\b ØDsz¦*\ 1Dûµ\ 4Ak\9e6IÀ@£g¿D8\87\ 4Ä'\1dMã!D\ 4ñÆO\ 3\rÖkÏ,\ 1ù9\8b/Eb\ 3\97S¬m\84cF6\9f\v\86¶¾*\86W\83\19BÁÆd\97O¯Ç\D¹wx«\98Ö\raç\ 4è .¸¦\ 6:\8f\0\1f6\ 2@{ǰ\1d}\89ñ°\19\1fìÂO÷}\12¹©ð\8a´]ö\88S Õ^\9a\5Äîé\9cÃÖ£2\9tsÔ\18oå\18\14b\93ÔK*\99x\ 5wfJ;\r\ 5\8bö\ 32`è\8eszýH}ü\ 6C\96ÇÚí\95Ú\96Ô\95r\aâb\9fØ\1e\15ÛcÝÒ3s¡P5ä}\13t\9b\9a@ R$\11k&\a7+eBrûÖ̰í)¬×\92>\85z\9bðÉA#IÑ\b\18§)qaQÞN¥»,\85\95*±ÅVëx\13.\85We\93¸ùåÿ`À\13í;q¬ª\80\ 2?\ 2CÑko4\96¤WÖVp\12\e\85Æ`\1d\92ï~V\85òá\8fÐ(\94\j×'§\94\7fB\15ÐSÐ4ß\fpAi\84Ý\80hé>"É\ 5º\ 6hÔ\7fÍ©Wç¢\ 3\19²\1c\0\14´M\1f\93\ 6\8c«Å\90-â\e0¦â\a\fdC«\bä.ÆdÌ,Ép=n×y\92E&íôöV[¬%y"¦Ùâ½\90ïSû=LD,\82®\92å±÷qt4:\ 2\13\94gg"Ýk+iµ¹÷.ÆnsÞõ\a\91¢\12ÆÅ\11Úq\f\9bG\11ÚyäÝå÷M^8øbÆÂ³ §Íê\1ai\ 5\17*6
+\81íèzàëØøÅ\89\1eÜÒîb¼\98`\11áÅR\85B\réx^3\1c[Ö¡Ò\0ï\9d° ¯k\17âKLÉb/|&¶YIFÛÔ×\86\8dêÖ8&\82\83\80å¾ÿ\1aúö X\¤\ 6\11Ú\9c¹$½od\98÷J&2\82\14«Íìt æ5/96\ 38\r(2í&+\84iW\ 1{)4«F~n\7f\92\14åÈ×ýmÎÆ\ 5V\81R¹\9d2Ý\947V1É×§0\19'0\89»U\1f8Â~\99\ 3\19ØÞÒð$rìºo\ 4\82ê\98Ϻü\82rîã\17Z\85¸\8eh Âj\14rÊ%£\1c\8eJéXÆ«$\8b\10×þÉZ¬¢pk°\8aJ\1e uU\97gFñø\að\ 3\96å5îìeä"òé*\91@\89(câ+Ó¤¼/þéÚ\14»?5¢Ô¯jEù_æi¥³3Øêpè<¥ü°\1eIÿ~\92\81³ ËrÌÜ0\15LÔ\859#ö|Êö\12äêDÔt\10ÓüôêÅ\9f\8d\ e\14Í\94\ 5\1c3 \7fæ+¦\8a\v.%\ 3\89\8e\15\14\bú\1aA\8b>\ 4YFYj\80ÀÜ\ 1`¯~zk\ 3tòçú\8bo\85ú'§\1a|S¬².\9e~]ûá\81\92f\8a\12È\9aÇ¥ÝÑåâ:þVrðô®EEÅ"\86]\12\15U\10\8d>r¢É$Ï\1cî÷U¾\9b³hp¿HâR\19ù@Ä«@å\0Üô¦iÙ,où)ª&í\1eK\15[\ 27\95\18\1c\98°KôK\12èSQ+\av0"f!&c\14ã8û\ 5<\15ð³·ÁH%¦kh\92-T¦®\81\93!àTì\8crÅv°ðeïX\88|\8cYj\94\#°¿£TµÛxêkLe\97\1eÈs_cªúð4N|\8d© ÏÓ8õ6¦\9cP³ñÒ×\98Ì\9f\arék\9cd\1f\ 4ÚNãk\7fcÔMMÈFÛº1-3´Ô\eEEù!;\18Ê5Ûu;ì\1d\83\81(ª'«é\94£w2p+_dN\ 5çØ`7ã¹ \98×ùÛ\19\ 3R\94\18ó\19h«ÑxI\90\9eô;\1a\9f(rBtj8\95\7f\1dÓ¤\1eR²5ú·{\8d´\8b\ 1mtÄì^ªÂ\0¾Ñ.\95=`\87\1eD\80áïÀ\9f\80pÿ\e<\ 4&¤\90\1c\f\95å\8b\8c\f\12©\88wÙ·Çà/Ô]=S\97ÔòN^\ fÖH5\19\r>µ=\14¹0]\89"#ó¢^\8e\10\915s²úä]ö®\92\ få\83\vUq§;Û³|ü.\13\b\18ôñQ\86ú\1e\881Â辫T¡»\ e,\8d..~xþâôâb\14í«\1a¼èñ¦\ 4\89¾=îf§\83á¡d¦\16^²XÉe£\a\ 1&j\80\91rÇ«3\90\0\90\ 37D\1cÚ
+9\1dC"Õ\888Ûs@e%\94ÄÙ2Å4\10î^\1aÒèÔ5ÝKJÉNB'5óÚB= wq2\11áó¡ÔºC©É\86Re\ fk58\14\18\r¥\8bçh\133zå!\8a®f\12z\12³á\89W\ 3u!·\ 5b6\89Ýr° r¼cp\9fbö!Û;üZ0¡s¼\94Xò\8e9¤é\9dO&2Í!¦u Ýsê8ì\10*1?\98\8f\86®)½áxà?SbQ\8d¶+\87k\1dÓG@\15ò0\rßX[>\7f\14dö\9b\13\ 3Q?'KOpD
+\94
+g\9d¤$\ få³_\a\1eIö\14%\bà\18Ðð\r*Ê\1d{\8fúä×ç¯\1fö\1cx§ñ*\82°ÁÝu ÷\0ìð.¹bÞâD¡\82T\rã\89\8a\9bÉ\1e~\8fQù\1aùÒr5Ôs0\19Õà`£Ó\95\93\89»\159\99LêZߨ
+õ» [ß¶\ 4·\16±qÌ\8aÎ\13\831ÄÈC5/òÕL×Ýa%?<\ 5%¬kÆiÐ$+yQ\89\10K¥R£Á\8d\8d\88eR\e\93\â£\ e\99\8al\84\e\ 1U\87d©\97v\17©\97ø¦çÑÖQ;Òò°-~Ãí.ìzßà\97ç4ý¼è\18]z¶\ 4äyö\81c«ÕßØÄº \fc$\8dÔ\99\8e*ÉD\fc.ÍD]¡\1c_±|àt#V Þq@\æyÊãL\80Èråøÿ2\17¥\94¸A-ð\84s\85'\ 3Ô1\r«ò®í\+\18\eZ×þæ°I\87#i\82ê ê_4¾²8Ö·\9b\95\ñå\97`äÞ\16&\9c
+Öà7à\90\90U·ª\84¼Ê¿1#õ¯BÖ»«Ý\811\99Ú«¼áãUQ\82d|¯XU±\8bBëqGGÕ¾î\aÍ\ 2\e\19"sÓ}A¸
+ªÁ°\ 4ISØ=\92°Õ*¶\81÷Ê\85\1aF\ 3ð\8eÔL\rj\a\bá£ûC\ 5\v\1e\ f\88âõ\8beu#\1d=*^¤d1æíÞð8}\1dWó\ 1ÖY\v®s~\ f¹Ä}8\ 3p#hg«K\ 4\86\87^\a»C1¼Á(\ 6;{ýhÿ7#«¹ä}²\9au±\ 6\ e\9cò\8a\12\9b²¬&\17!8\16\11rÑçInZÔòÙ®¸\8eØ´\9a+:r\15ëSµí\96α2a\v\13Pñuü\84:\88o2#n\17\ 49ýDÞTõ\13ß(ì\1eê@óÑ\1dôìð\V.ëB|õƺ\7fm\aDþ°¶\ 5åxÎ\8dóù>´\959ø\1c¦@\88\87×\1e\10YZe"¤â%}\8fÔ=\16i<æ\83\bÜý!f\8a\15h\83Y)\99?\10#ïí±cv\80\86\0¤Ö8{!Ñ\ 1\0»ÆÑ\8b\86VÓCË=±\9aÅÒÚ
+S\1c\85,\91\9e\v\f¨:\1f\19\9b\aÚåܹ#¬\ eF\17\fåÇÇó\9cÝ\17½h¯oû\96çâÉ{\7f¨\89Ôb\8d\91ÚYh\eu[{ \85\ 5yÈÊ\vá\93?bC\11\18úVv\15Þ\8cjßËf\88ûÁ\ 6\à
+ºêî\14WÕuQý\82½³\14N\9aë\ 3ÊKF.¨2agjIb+.Àò\19\8a\9c+Q\92Ó¦\9di¿ tmPÜéj\ f§¶9\8dË_H?L<\r\ 3\1a=è\ 5IgIxô¡6Ý»
+\87×p¶ì\a5e4£x-M.\12Áb\9bdÎJ\ 2\94YL\1f@J7j\80:¹Ù\9eÇi\92zÐN\87¡À|(1qNÈ5\94ªÚ\10õI,(§% ÿ\7fÌ\11m¸\9d \9axzpÚT¤iz\ 1\eÉâ\ 2\89?\90K åNÜÌÔÜ ô.ÅÀê\ 1W°*P]ÚE{¨\17ªQ°\1eã\17Ì â\ 5Tx,Õ\90»\83\aË,pP¦Ì\ fzIN\9dÅ\16õ\ 4]\93Ö\95Z-\13¯+\bÒºQw¹@Û\94\eÕ\ 2?$ºN`U¤QGh§-OÛ5ã7«Ì;YÌ\17\9b\91ߦfî\93%öN:\bÖ®t@1Ó*ÿmÁµjj\1e\86\ fdFw\87\8db\1c©³¨\83$°6iî\r3\e°\99 *±x\ 5\18wÈ\17{«Ú\ 4Å\8b\f\90YñDâP\e8\1cEV²lVð\84\0\82\92\88wÙ\85F»%\89ì"\93\96ÈnZ\9dhÁL2öó\9b\17LÔ\95õ¯èi£Åg\14Ñ.\12 \88\1a³×¾Î\99\f\9c6\ 5I\9e\v®WnVÄËyâÆ!-a×¢ö\fÛ*Y[K\1fôV\v^Bo¢\16,\ÿ9ô\82)\üº*âq\97\99e§F³ w{\14\81yS\r\r%\ 2\19zÕûk\ 1\89hP\11H\f\95Ü«ó\9fÎp[¨\81\1e\94ªÅÛ¦\97Q%å\96÷Q}ºD]\rÛØ\bØ¥\82@\8cîÝÚ$DÓ`\89 ¡Q6\f\94·\ 2Â\92`Y ýX]\a\13\8ddÉ ùg7ÕWÃè\9fê½\17Ý\0#H
+\1f\arÛK\89\9bwÑè]´kÖÒmW>צB\ 2\f\83º2À\1eøÈ^KaL)zw\12\88ûÝ\8e\e\14d\ 5±¡\bU'5H'6)ª\96\0Ãô¾¢¢q¾Ê*ñ\18#Ò\87\9dGð~ÊRØ*g Ï\80\ 2¯Ìì]\9aæ\1fùdä9\8a\17¬³\90s\82\7fÎ\ f\9c#꾫>jbÐB\1c)6÷\16¸]b(çH%D\ 1W\8c\89SÂÜLs\ò̼D\ 5;©ã´Qw;\8aûá£ÝæÀ*V'\9a\1eÈ\86N ÔÎeÊ3\ 1\97®¶ÀÆVéX\7fC×\92¤Áî®!\v\191Á~Q 9¢+2\rµ¡[Ó\9dq\87rÅò´Ö\18q3©Z+ðF>Y«\1aq\98\ 5·\84rGh\94ÉÚP)©,kÝÕYõFq²ê:áKX@º¡[\9e-æÅ"¡\80w)~\8añò\82tÂCÇ\95ë\0[àÁ\94~ÖÑxã \95\1dß\91EêÂÐ[\93y\82üd\9c˱÷Ù]k1p"\ 6®\ e"neZðL\99\95 CýìÐ*Ü\14u\9bµPÐ0\bÍ\94\ 5©R\84B`#:\805¢Î\ 1ýfÝ\ 2¢Êa$\98æ}Oª¼êc\91T\98\9aêî\81\7f¶öÓ^3(ÎtÂäe}*Á5ñ\1dC6¿Y_\16W\98\10n ÑZ\9c,C¦@\92û!\9a|7Î\97 ©¸\86
+¤3-\ 1\84\8dF#\9a\96UÐçÕÕu\87üÊn½\91\13\87^ä\84#Á\Ùÿ\9e~¥Óÿ\94´ ó+q}vÃ9lÖâþ6Ïíw{¶\ 2§\90c\eIä,ÌÌm´¹Kë§\ 6eÕÀ«U~{}÷\ 5¸\9aÔŸ¡Ýï£\9a\9a@\9e\80ª,¯Õ>\91Ûí©¶Ó¨é§\9eºnê&\ e\\v³Ð\8dTôF\83ÆÞ\12,\89xÓAEÛ!ÙØÈ¤ÖÇ£|ùÜnW-@\v]\1fÞ]\84¯òzVKî\89g\aKÈåóUFáh3?U?l« ÛDv=\95`°ùBÆDN\95i[u\v\87+\86-2ëÙ²N9\95¾õ\16a¬\ 3
+mL1ã/oûeõ\89<¹?ÝfC\1a¨\8c\93\ 5\ 3±óò\81n\19óM¢í°X\92z7\83ýö\80ø÷ÿÇÃ>Ïñ0c16ÝÉZ
+§\95Ñ\1cùR[Xcû*j)t\1d\8bjé/géV\7f^6U\99~G§\8d}ÚOUÆôÑ\94ëä U\ 1M\9fóG=r\8aF[QõÙ÷\8cPç\91\9fÏXìïT2þc\vüÃÈÔ\82`\7fº\952æ\10ó¢¡ÀÒ»\v°\99®<©@9<_\1a1\1f³\82©Å\82\89K¶1,R\9b²~\ 2eâ\14´`\ 6r\97F²\93\90Cÿ¼y\9e\1c\94[\96\eª\15õ\9c|©\8c¸ä\9b@\91Î++P\ fõ¹r|ÃT\97Q\fM\ 6\8dX\17\81µ3\8b\rÛ)ë\9eÃ&\9c{QÕDd\8dàjÙbNë³\86âæ¢å£ý}"]´½²·õk\88\82f \eÚi¦s\89\88ñÈÆY¦Ý^t3\87\ fø·}\94¶¬ª\ e\9eÕl\88{¿\ 3W\eËû¬IÌg¼²r#\842]\13Ð!î±Ï]5\ 4ÓÕ\1a=Å\7fÖ"þϺÄ?$ÿ°íë§\0p\7fx»\1a \85ä}4\80\19î²Ó-òr(Y©\8a úQÚÄì_S%xHê¦\80Ïj\8a2\93ì5ù\ 4¯çt®\9f/Ô\1d%&\19õR¨À£êJspµL-âë)\18\\ 5\7f¬ñöµ\f©\15\10\ 4G\f\8d\1c\81Ð\91[è\19åã´\10æq\9f\9aíÌKù\8cvº¾Ú\13Ï\rh¥\93\96¼o\7fM¤\ 6\ ej"\85=\1eõ©\8fÀÑ{óÄÖIØiuã\13\ 5$¶Q%ãn¢\9e\143\97¨~eÒÌÚ\8eínÝú£\8b>Mõñ\94ßF\1c¬\ fs¡ø\87è`d(×\92Ôà|?G¨ë\ f8\8ej\14p\8a¢ýàAôµkÍÛ¯×Zç\18lç}[õ4×c¿\95ù\a\vÞ7!A\18X\1f*\ 4ëé·\98èÏZñɦ³ìw:¸çÅj\ey½É¬Q\1aß(ÜÕ\a\8c70-¥êÛ·\9eÜÅ®u¯[C·_\12¸\95WÚA\12]Dx¦\1a\86\fÉ\89eD\*öðB[¦ß´ ?Þ\86\ 1é\9a<ù\8e!v ëÑ<\96î¿Î±\v\8b-v\95Ä\v-·\16Ù û\9c¡ßD´ðU}]»stôèU~gÍÝy\9bpõ\96 \85D«\14-ôË\ 4ë=£°Æuu®ªÒ\13W\ f\1aï\17¤ÐÑFÁ%\14\8azèp\88É\aY½Ý\8f^x'@Þ`(..ªdLQxñ&JySâÕ\bH-o(\8cEv\80\86¦\91a8ÿ\1d\89Ká\9cÂÆçRÞt\88R\1dË\97é\ 13ô¥ì"5 ÆÔè\ 3Ý){\10¸óÐÂ\0\v\ 5ä{è\90êtBXÞÅ&\86U×¹\8bb\14\91\96@ >à&`\ 5\94òÃl\9a\ 2 \ 4æúÎHÉ
+âWèq8b'HVE» þbaiº\b*¾\82ÿ\8b¤LzÃ\8aX\1cÕÄQ\149\14Ól£\9eû\88\95VÑ\1d²\15,Ó$¶¬#fݪºKÎ\9aê\9a_½¼\r\85\r\ 3wQ\ 3u6\12"\10\ 1ôf"\ 2:ý¥d,?\0#\14ß[Õ\a w\9b;\aÝR\b¨ÓòÊ×\928Àm¹Ø<\93£\8f\83M<gÁzy¡tn×öBÁB©\15 _\f°\93§\13UæXw\9dÕ\8b¹¾ó* êwÚ5:[¿\ 4Aé m0\91?t\ 2w\e\8beäå\0TgYXôÒPÈ\96\12\16÷¹ÇÊt\18\87.b¼"²\a¾¸ýÅ\15\88Á¹`,z1\1er®ÝA0ó\11µìHó©¦X."µõ\80~ë¾\12³\95\81\9bÛ'½x\rð^¼\1a*¨\ 5MÊY:\9c¨®\98ªräfëùqÒ{X\88\9e\81J\90Nÿ®+%@kj\84\b{¸yIfúxX\ 65òº\ 1\1dé\ 3¿\8b×L"\88ë=þÕ¼<}I«\18_\15A6ÆÐ®P\9c¹þ³tãèØ+Bß\11}M\17rÓ{\ 6j
+\ 6&¡|¼\16\97n[\8f«\83ÿ¡\9dââ\8d|-è×?;ÓÅô>gë\96|NB(gËC\b\7fpÕð¡Îw®]£îs´,Ë·\9e£åMiýC\1cþ¦\83ìíº\8e\ f\95\7f¸·\80Úf\9dÄÕ°r-þQ\97uªQ¼\1dÔ´ÁnuuB\17\ etx\98þ\ 6N#D@9\15A\87\8c(h5mºRzÆ\aë:i^:5i\15\84ᮯã.Ø\906\8f \92\Mxã=[>ï@5[ß;\80\9ezøõ\9c\ 3è\19t\ edÁúúþAÈ`c©ä\95S*éZá\90Åõ\ 2TfØ\e_\11åÕÒ{ðáRæ00\15h¢;-\9b{\rä\ 1£·2\7fLðªÅêvL¦\9f)\9e2#\1f)\99BÕ®÷ÏH.,nêi2[Xá³\9aÌ\ eéP&óû¦t8¦\11\0µ\9bF_\83\9e¦ÑG\9c\7f\ 5ÓØK«¯m?ñ¯§\ 2¦I\99\ 6+\18dht\ 3\ 6ú®Ê'âJ9Ú*\ 3cÓÝ~\f\84\917dÚÝ{\93Jß\0ýÆOòt\84eõ\9a\1dרÄÒ8AË\84\989À,Îeß\82BzÔ¸
+ß¼k1à\85¬Á\rÛsA;\e¬±ü'îòÿ3.ü,øÚ\v½±_\82ö¼¡u_Ø>ÉsÕf7dUòô\9c*\eZ#¡\8bÝZC\15¦\17"Fëçx<¹©Ó\15Â~/ó²Läý¢Ê\982l\92ÊMý6öÝK\§Öèy竤\9afÝ$kÿýp\eU\9b\86ýVìz\17\ 1Цû¸K\97
+ÚU\82Ý6Ú;Ç5ìs\7f«+_|cj1\9d\1d¶n\ 6 "`3\8cl\19îº÷ ¾î¥©`Eÿó\88\1eSeh£Kp¯wÏ\7f%¼\84ø#<Û£Ã[Toúê§W§F¡©?¾êíJ£\9cGøÿ\vñãã`/·\83ÙÖ¼~~\Ân\8c!}\ f\fZ®¼¿Òå\13Í_åÏ\ e\ 4ï¯\vï¯òu\91zí¢g¿FGÇøö\84'¿>ÄOæbª\93/}®P s1 Í\8d\95!4\1e<°ÉGl\ 2÷\8e\93ò©QKä\7fu\8f\17\84AÒ\aGL\0\9b\99EXg¸÷õ\984ÿØXh\16L¿Hª\9d#µÞû\10©_HÙ\84,ë·º\81ã
+ø¡÷³µ\92\11z\12ÊG\9e\96\13ù\92O» \ 4V¹Óß\92ìêâî}'\87\92½Sq`\15ÄÏø;\92\1cçj«óȬZÛ£R\!¸«@û§ÍÖ\ 2|wûÙo
+©#\87yZ»aâûF7b\8b\8eéàÚ`×#¹NèÆb\98öæ`\8cö(/' \97Kð\8dªé úbô§Ù\17_à\15/\82/¾\85\95\16<ö\15;<8ØeûêÉ#úÞ\1cAñÃÞ,Í/é\80\03L\8fÅ0\b³\ 5@½:\ 4`\11X\1f¬_7æ®ÖG]/Ó¬s÷íFÃ1Æ{º\ 5\8eÖ\16@´®ÍxÃÿ¶â%\ 6gDDÆN\83øn\f²]y\11\89´\ 6µÛ7B\90¾;\83RÛL\18G\1eÑУjÿ8OÆsº`\15ðl(yì¿\88¯\a\8a\98Ô\1aï×OÛ\a^w 1[ÑdÄ¢Gôöwqç8\8f«AÄ\90#S¼H\88í1\e\19¼2\1fAÊ\9bó]´,WðÓ]ùáÛã»ÿ\v\8d\92AO\83@\10\85Ïì¯\98£6±T/\1e4ÖÚ\8b\1e\9a4ö\a\98)\f°qYÈì.j\88ÿÝ\81jj iË\85ÌûÞ¼}K¸\9f×ET<\99(\98Àc¦\rA] OµMzEÛ\9c«PÃZÄ^ز¦\f\12\83ÎíE\f¾¨\18`\85\9c\ 4\aO\15qN;\94¢'\90çf6»\85«þ%z\87ºmXVe\896\959Vq\fmÛþË\ 6úôdS\19\9e×o\vN
+ÝÐ_×\9e÷Ön:Ö\15v^]Ö\86J²\1e½®ì©Ú\r±\13\e\Og}·ã¥öá\ e^) ²ÛÐ\8b'F_±jU\94\ 5\9btÇBN~£s\8b>0]\ªHXÄ$\93\85\f\8d£;\15}«CÿÂhtçx\99>´M\7f\9d\a¤A£Ós"¤:Ë-Æ2ÞékL¶ò9Æô\ 2ݲÐ&\95¸3ï9°\ fÓVäQ~&\1cò}\ 2o|Ø\8e!7@\ 2ç\ f?¨ C\82
+¤Z·×\80ø@ï\8b\9dø\99\10ï³\ 2\0\0\0GBMB
\ No newline at end of file
+++ /dev/null
-<?php
-/** @file phar.php
- * @ingroup Phar
- * @brief class Phar Pre Command
- * @author Marcus Boerger
- * @date 2007 - 2007
- *
- * Phar Command
- */
-foreach(array("SPL", "Reflection", "Phar") as $ext)
-{
- if (!extension_loaded($ext))
- {
- echo "$argv[0] requires PHP extension $ext.\n";
- exit(1);
- }
-}
-
-if (!class_exists('DirectoryTreeIterator', 0))
-{
-
-/** @file directorytreeiterator.inc
- * @ingroup Examples
- * @brief class DirectoryTreeIterator
- * @author Marcus Boerger
- * @date 2003 - 2005
- *
- * SPL - Standard PHP Library
- */
-
-/** @ingroup Examples
- * @brief DirectoryIterator to generate ASCII graphic directory trees
- * @author Marcus Boerger
- * @version 1.1
- */
-class DirectoryTreeIterator extends RecursiveIteratorIterator
-{
- /** Construct from a path.
- * @param $path directory to iterate
- */
- function __construct($path)
- {
- parent::__construct(
- new RecursiveCachingIterator(
- new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::KEY_AS_FILENAME
- ),
- CachingIterator::CALL_TOSTRING|CachingIterator::CATCH_GET_CHILD
- ),
- parent::SELF_FIRST
- );
- }
-
- /** @return the current element prefixed with ASCII graphics
- */
- function current()
- {
- $tree = '';
- for ($l=0; $l < $this->getDepth(); $l++) {
- $tree .= $this->getSubIterator($l)->hasNext() ? '| ' : ' ';
- }
- return $tree . ($this->getSubIterator($l)->hasNext() ? '|-' : '\-')
- . $this->getSubIterator($l)->__toString();
- }
-
- /** Aggregates the inner iterator
- */
- function __call($func, $params)
- {
- return call_user_func_array(array($this->getSubIterator(), $func), $params);
- }
-}
-
-}
-
-if (!class_exists('DirectoryGraphIterator', 0))
-{
-
-/** @file directorygraphiterator.inc
- * @ingroup Examples
- * @brief class DirectoryGraphIterator
- * @author Marcus Boerger
- * @date 2003 - 2005
- *
- * SPL - Standard PHP Library
- */
-
-/** @ingroup Examples
- * @brief A tree iterator that only shows directories.
- * @author Marcus Boerger
- * @version 1.1
- */
-class DirectoryGraphIterator extends DirectoryTreeIterator
-{
- function __construct($path)
- {
- RecursiveIteratorIterator::__construct(
- new RecursiveCachingIterator(
- new ParentIterator(
- new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::KEY_AS_FILENAME
- )
- ),
- CachingIterator::CALL_TOSTRING|CachingIterator::CATCH_GET_CHILD
- ),
- parent::SELF_FIRST
- );
- }
-}
-
-}
-
-if (!class_exists('InvertedRegexIterator', 0))
-{
-
-/** @file invertedregexiterator.inc
- * @ingroup Phar
- * @brief class InvertedRegexIterator
- * @author Marcus Boerger
- * @date 2007 - 2007
- *
- * Inverted RegexIterator
- */
-
-/** @ingroup Phar
- * @brief Inverted RegexIterator
- * @author Marcus Boerger
- * @version 1.0
- */
-class InvertedRegexIterator extends RegexIterator
-{
- /** @return !RegexIterator::accept()
- */
- function accept()
- {
- return !RegexIterator::accept();
- }
-}
-
-}
-
-if (!class_exists('CLICommand', 0))
-{
-
-/** @file clicommand.inc
- * @ingroup Phar
- * @brief class CLICommand
- * @author Marcus Boerger
- * @date 2007 - 2007
- *
- * Phar Command
- */
-
-/** @ingroup Phar
- * @brief Abstract base console command implementation
- * @author Marcus Boerger
- * @version 1.0
- */
-abstract class CLICommand
-{
- protected $argc;
- protected $argv;
- protected $cmds = array();
- protected $args = array();
- protected $typs = array();
-
- function __construct($argc, array $argv)
- {
- $this->argc = $argc;
- $this->argv = $argv;
- $this->cmds = self::getCommands($this);
- $this->typs = self::getArgTyps($this);
-
- if ($argc < 2) {
- self::error("No command given, check ${argv[0]} help\n");
- } elseif (!isset($this->cmds[$argv[1]]['run'])) {
- self::error("Unknown command '${argv[1]}', check ${argv[0]} help\n");
- } else {
- $command = $argv[1];
- }
-
- if (isset($this->cmds[$command]['arg'])) {
- $this->args = call_user_func(array($this, $this->cmds[$command]['arg']));
- $i = 1;
- $missing = false;
- while (++$i < $argc) {
- if ($argv[$i][0] == '-') {
- if (strlen($argv[$i]) == 2 && isset($this->args[$argv[$i][1]])) {
- $arg = $argv[$i][1];
- if (++$i >= $argc) {
- self::error("Missing argument to parameter '$arg' of command '$command', check ${argv[0]} help\n");
- } else {
- $this->args[$arg]['val'] = $this->checkArgTyp($arg, $i, $argc, $argv);
- }
- } else {
- self::error("Unknown parameter '${argv[$i]}' to command $command, check ${argv[0]} help\n");
- }
- } else {
- break;
- }
- }
- if (isset($this->args[''])) {
- if ($i >= $argc) {
- if (isset($this->args['']['require']) && $this->args['']['require']) {
- self::error("Missing default trailing arguments to command $command, check ${argv[0]} help\n");
- }
- } else {
- $this->args['']['val'] = array();
- while($i < $argc) {
- $this->args['']['val'][] = $argv[$i++];
- }
- }
- } else if ($i < $argc) {
- self::error("Unexpected default arguments to command $command, check ${argv[0]} help\n");
- }
-
- foreach($this->args as $arg => $inf) {
- if (strlen($arg) && !isset($inf['val']) && isset($inf['required']) && $inf['required']) {
- $missing .= "Missing parameter '-$arg' to command $command, check ${argv[0]} help\n";
- }
- }
- if (strlen($missing))
- {
- self::error($missing);
- }
- }
-
- call_user_func(array($this, $this->cmds[$command]['run']), $this->args);
- }
-
- static function notice ($msg)
- {
- fprintf(STDERR, $msg);
- }
-
- static function error ($msg, $exit_code = 1)
- {
- notice($msg);
- exit($exit_code);
- }
-
- function checkArgTyp($arg, $i, $argc, $argv)
- {
- $typ = $this->args[$arg]['typ'];
-
- if (isset($this->typs[$typ]['typ'])) {
- return call_user_func(array($this, $this->typs[$typ]['typ']), $argv[$i], $this->args[$arg], $arg);
- } else {
- return $argv[$i];
- }
- }
-
- static function getSubFuncs(CLICommand $cmdclass, $prefix, array $subs)
- {
- $a = array();
- $r = new ReflectionClass($cmdclass);
- $l = strlen($prefix);
-
- foreach($r->getMethods() as $m)
- {
- if (substr($m->name, 0, $l) == $prefix)
- {
- foreach($subs as $sub)
- {
- $what = substr($m->name, $l+strlen($sub)+1);
- $func = $prefix . $sub . '_' . $what;
- $what = str_replace('_', '-', $what);
- if ($r->hasMethod($func))
- {
- if (!isset($a[$what]))
- {
- $a[$what] = array();
- }
- $a[$what][$sub] = /*$m->class . '::' .*/ $func;
- }
- }
- }
- }
- return $a;
- }
-
- static function getCommands(CLICommand $cmdclass)
- {
- return self::getSubFuncs($cmdclass, 'cli_cmd_', array('arg','inf','run'));
- }
-
- static function getArgTyps(CLICommand $cmdclass)
- {
- return self::getSubFuncs($cmdclass, 'cli_arg_', array('typ'));
- }
-
- static function cli_arg_typ_bool($arg, $cfg, $key)
- {
- return (bool)$arg;
- }
-
-
- static function cli_arg_typ_int($arg, $cfg, $key)
- {
- if ((int)$arg != $arg) {
- self::error("Argument to -$key must be an integer.\n");
- }
-
- return (int)$arg;
- }
-
- static function cli_arg_typ_regex($arg, $cfg, $key)
- {
- if (strlen($arg))
- {
- if (strlen($arg) > 1 && $arg[0] == $arg[strlen($arg)-1] && strpos('/,', $arg) !== false)
- {
- return $arg;
- }
- else
- {
- return '/' . $arg . '/';
- }
- }
- else
- {
- return NULL;
- }
- }
-
- static function cli_arg_typ_select($arg, $cfg, $key)
- {
- if (!in_array($arg, array_keys($cfg['select']))) {
- self::error("Parameter value '$arg' not one of '" . join("', '", array_keys($cfg['select'])) . "'.\n");
- }
- return $arg;
- }
-
- static function cli_arg_typ_dir($arg, $cfg, $key)
- {
- $f = realpath($arg);
-
- if ($f===false || !file_exists($f) || !is_dir($f)) {
- self::error("Requested path '$arg' does not exist.\n");
- }
- return $f;
- }
-
- static function cli_arg_typ_file($arg)
- {
- $f = new SplFileInfo($arg);
- $f = $f->getRealPath();
- if ($f===false || !file_exists($f))
- {
- echo "Requested file '$arg' does not exist.\n";
- exit(1);
- }
- return $f;
- }
-
- static function cli_arg_typ_filenew($arg, $cfg, $key)
- {
- $d = dirname($arg);
- $f = realpath($d);
-
- if ($f === false) {
- self::error("Path for file '$arg' does not exist.\n");
- }
- return $f . substr($arg, strlen($d));;
- }
-
- static function cli_arg_typ_filecont($arg, $cfg, $key)
- {
- return file_get_contents(self::cli_arg_typ_file($arg, $cfg, $key));
- }
-
- function cli_get_SP2($l1, $arg_inf)
- {
- return str_repeat(' ', $l1 + 2 + 4 + 8);
- }
-
- function cli_get_SP3($l1, $l2, $arg_inf)
- {
- return str_repeat(' ', $l1 + 2 + 4 + 8 + 2 + $l2 + 2);
- }
-
- static function cli_cmd_inf_help()
- {
- return "This help or help for a selected command.";
- }
-
- private function cli_wordwrap($what, $l, $sp)
- {
- $p = max(79 - $l, 40); // minimum length for paragraph
- $b = substr($what, 0, $l); // strip out initial $l
- $r = substr($what, $l); // remainder
- $r = str_replace("\n", "\n".$sp, $r); // in remainder replace \n's
- return $b . wordwrap($r, $p, "\n".$sp);
- }
-
- private function cli_help_get_args($func, $l, $sp, $required)
- {
- $inf = "";
- foreach(call_user_func($func, $l, $sp) as $arg => $conf)
- {
- if ((isset($conf['required']) && $conf['required']) != $required)
- {
- continue;
- }
- if (strlen($arg))
- {
- $arg = "-$arg ";
- }
- else
- {
- $arg = "... ";
- }
- $sp2 = $this->cli_get_SP2($l, $inf);
- $l2 = strlen($sp2);
- $inf .= $this->cli_wordwrap($sp . $arg . $conf['inf'], $l2, $sp2) . "\n";
- if (isset($conf['select']) && count($conf['select']))
- {
- $ls = 0;
- foreach($conf['select'] as $opt => $what)
- {
- $ls = max($ls, strlen($opt));
- }
- $sp3 = $this->cli_get_SP3($l, $ls, $inf);
- $l3 = strlen($sp3);
- foreach($conf['select'] as $opt => $what)
- {
- $inf .= $this->cli_wordwrap($sp2 . " " . sprintf("%-${ls}s ", $opt) . $what, $l3, $sp3) . "\n";
- }
- }
- }
- if (strlen($inf))
- {
- if ($required)
- {
- return $sp . "Required arguments:\n\n" . $inf;
- }
- else
- {
- return $sp . "Optional arguments:\n\n". $inf;
- }
- }
- }
-
- function cli_cmd_arg_help()
- {
- return array('' => array('typ'=>'any','val'=>NULL,'inf'=>'Optional command to retrieve help for.'));
- }
-
- function cli_cmd_run_help()
- {
- $argv = $this->argv;
- $which = $this->args['']['val'];
- if (isset($which))
- {
- if (count($which) != 1) {
- self::error("More than one command given.\n");
- }
-
- $which = $which[0];
- if (!array_key_exists($which, $this->cmds)) {
- self::error("Unknown command, cannot retrieve help.\n");
- }
-
- $l = strlen($which);
- $cmds = array($which => $this->cmds[$which]);
- } else {
- echo "\n$argv[0] <command> [options]\n\n";
- $l = 0;
- ksort($this->cmds);
- foreach($this->cmds as $name => $funcs) {
- $l = max($l, strlen($name));
- }
- $inf = "Commands:";
- $lst = "";
- $ind = strlen($inf) + 1;
- foreach($this->cmds as $name => $funcs)
- {
- $lst .= ' ' . $name;
- }
- echo $this->cli_wordwrap($inf.$lst, $ind, str_repeat(' ', $ind)) . "\n\n";
- $cmds = $this->cmds;
- }
- $sp = str_repeat(' ', $l + 2);
- foreach($cmds as $name => $funcs)
- {
- $inf = $name . substr($sp, strlen($name));
- if (isset($funcs['inf']))
- {
- $inf .= $this->cli_wordwrap(call_user_func(array($this, $funcs['inf'])), $l, $sp) . "\n";
- if (isset($funcs['arg']))
- {
- $inf .= "\n";
- $inf .= $this->cli_help_get_args(array($this, $funcs['arg']), $l, $sp, true);
- $inf .= "\n";
- $inf .= $this->cli_help_get_args(array($this, $funcs['arg']), $l, $sp, false);
- }
- }
- echo "$inf\n\n";
- }
- exit(0);
- }
-
- static function cli_cmd_inf_help_list()
- {
- return "Lists available commands.";
- }
-
- function cli_cmd_run_help_list()
- {
- ksort($this->cmds);
- $lst = '';
- foreach($this->cmds as $name => $funcs) {
- $lst .= $name . ' ';
- }
- echo substr($lst, 0, -1) . "\n";
- }
-}
-
-}
-
-if (!class_exists('PharCommand', 0))
-{
-
-/**
- * @file pharcommand.inc
- * @ingroup Phar
- * @brief class CLICommand
- * @author Marcus Boerger
- * @date 2007 - 2007
- *
- * Phar Command
- */
-// {{{ class PharCommand extends CLICommand
-/**
- * PharCommand class
- *
- * This class handles the handling of the phar
- * commands. It will be used from command line/console
- * in order to retrieve and execute phar functions.
- *
- * @ingroup Phar
- * @brief Phar console command implementation
- * @author Marcus Boerger
- * @version 1.0
- */
-class PharCommand extends CLICommand
-{
- // {{{ public function cli_get_SP2
- public function cli_get_SP2($l1, $arg_inf)
- {
- return str_repeat(' ', $l1 + 2 + 4 + 9);
- }
- // }}}
- // {{{ public function cli_get_SP3
- /**
- * Cli Get SP3
- *
- * @param string $l1 Eleven
- * @param string $l2 Twelve
- * @param string $arg_inf
- * @return string The repeated string.
- */
- function cli_get_SP3($l1, $l2, $arg_inf)
- {
- return str_repeat(' ', $l1 + 2 + 4 + 9 + 2 + $l2 + 2);
- }
- // }}}
- // {{{ static function phar_args
- /**
- * Phar arguments
- *
- * This function contains all the phar commands
- *
- * @param string $which Which argument is chosen.
- * @param string $phartype The type of phar, specific file to work on
- * @return unknown
- */
- static function phar_args($which, $phartype)
- {
- $phar_args = array(
- 'a' => array(
- 'typ' => 'alias',
- 'val' => NULL,
- 'inf' => '<alias> Provide an alias name for the phar file.'
- ),
- 'c' => array(
- 'typ' => 'compalg',
- 'val' => NULL,
- 'inf' => '<algo> Compression algorithm.',
- 'select' => array(
- '0' => 'No compression',
- 'none' => 'No compression',
- 'auto' => 'Automatically select compression algorithm'
- )
- ),
- 'e' => array(
- 'typ' => 'entry',
- 'val' => NULL,
- 'inf' => '<entry> Name of entry to work on (must include PHAR internal directory name if any).'
- ),
- 'f' => array(
- 'typ' => $phartype,
- 'val' => NULL,
- 'inf' => '<file> Specifies the phar file to work on.'
- ),
- 'h' => array(
- 'typ' => 'select',
- 'val' => NULL,
- 'inf' => '<method> Selects the hash algorithmn.',
- 'select' => array('md5' => 'MD5','sha1' => 'SHA1')
- ),
- 'i' => array(
- 'typ' => 'regex',
- 'val' => NULL,
- 'inf' => '<regex> Specifies a regular expression for input files.'
- ),
- 'k' => array(
- 'typ' => 'any',
- 'val' => NULL,
- 'inf' => '<index> Subscription index to work on.',
- ),
- 'l' => array(
- 'typ' => 'int',
- 'val' => 0,
- 'inf' => '<level> Number of preceeding subdirectories to strip from file entries',
- ),
- 'm' => array(
- 'typ' => 'any',
- 'val' => NULL,
- 'inf' => '<meta> Meta data to store with entry (serialized php data).'
- ),
- 'p' => array(
- 'typ' => 'loader',
- 'val' => NULL,
- 'inf' => '<loader> Location of PHP_Archive class file (pear list-files PHP_Archive).'
- .'You can use \'0\' or \'1\' to locate it automatically using the mentioned '
- .'pear command. When using \'0\' the command does not error out when the '
- .'class file cannot be located. This switch also adds some code around the '
- .'stub so that class PHP_Archive gets registered as phar:// stream wrapper '
- .'if necessary. And finally this switch will add the file phar.inc from '
- .'this package and load it to ensure class Phar is present.'
- ,
- ),
- 's' => array(
- 'typ' => 'file',
- 'val' => NULL,
- 'inf' => '<stub> Select the stub file.'
- ),
- 'x' => array(
- 'typ' => 'regex',
- 'val' => NULL,
- 'inf' => '<regex> Regular expression for input files to exclude.'
- ),
-
- );
-
- if (extension_loaded('zlib')) {
- $phar_args['c']['select']['gz'] = 'GZip compression';
- $phar_args['c']['select']['gzip'] = 'GZip compression';
- }
-
- if (extension_loaded('bz2')) {
- $phar_args['c']['select']['bz2'] = 'BZip2 compression';
- $phar_args['c']['select']['bzip2'] = 'BZip2 compression';
- }
-
- $hash_avail = Phar::getSupportedSignatures();
- if (in_array('SHA-256', $hash_avail)) {
- $phar_args['h']['select']['sha256'] = 'SHA256';
- }
-
- if (in_array('SHA-512', Phar::getSupportedSignatures())) {
- $phar_args['h']['select']['sha512'] = 'SHA512';
- }
-
- $args = array();
-
- foreach($phar_args as $lkey => $cfg) {
- $ukey = strtoupper($lkey);
- $required = strpos($which, $ukey) !== false;
- $optional = strpos($which, $lkey) !== false;
-
- if ($required || $optional) {
- $args[$lkey] = $cfg;
- $args[$lkey]['required'] = $required;
- }
- }
- return $args;
- }
- // }}}
- // {{{ static function strEndsWith
- /**
- * String Ends With
- *
- * Wether a string end with another needle.
- *
- * @param string $haystack The haystack
- * @param string $needle The needle.
- * @return mixed false if doesn't end with anything, the string
- * substr'ed if the string ends with the needle.
- */
- static function strEndsWith($haystack, $needle)
- {
- return substr($haystack, -strlen($needle)) == $needle;
- }
- // }}}
- // {{{ static function cli_arg_typ_loader
- /**
- * Argument type loader
- *
- * @param string $arg Either 'auto', 'optional' or an filename that
- * contains class PHP_Archive
- * @param string $cfg Configuration to pass to a new file
- * @param string $key The key
- * @return string $arg The argument.
- */
- static function cli_arg_typ_loader($arg, $cfg, $key)
- {
- if (($arg == '0' || $arg == '1') && !file_exists($arg)) {
- $found = NULL;
- foreach(split("\n", `pear list-files PHP_Archive`) as $ent) {
- $matches = NULL;
- if (preg_match(",^php[ \t]+([^ \t].*pear[\\\\/]PHP[\\\\/]Archive.php)$,", $ent, $matches)) {
- $found = $matches[1];
- break;
- }
- }
- if (!isset($found)) {
- $msg = "Pear package PHP_Archive or Archive.php class file not found.\n";
- if ($arg == '0') {
- self::notice($msg);
- } else {
- self::error($msg);
- }
- }
- $arg = $found;
- }
- return self::cli_arg_typ_file($arg);
- }
- // }}}
- // {{{ static function cli_arg_typ_pharnew
- /**
- * Argument type new phar
- *
- * @param string $arg The new phar component.
- * @param string $cfg Configuration to pass to a new file
- * @param string $key The key
- * @return string $arg The new argument file.
- */
- static function cli_arg_typ_pharnew($arg, $cfg, $key)
- {
- $arg = self::cli_arg_typ_filenew($arg, $cfg, $key);
- if (!Phar::isValidPharFilename($arg)) {
- self::error("Phar files must have file extension '.phar', '.phar.php', '.phar.bz2' or 'phar.gz'.\n");
- }
- return $arg;
- }
- // }}}
- // {{{ static function cli_arg_typ_pharfile
- /**
- * Argument type existing Phar file
- *
- * Return filenam eof an existing Phar.
- *
- * @param string $arg The file in the phar to open.
- * @param string $cfg The configuration information
- * @param string $key The key information.
- * @return string $pharfile The name of the loaded Phar file.
- * @note The Phar will be loaded
- */
- static function cli_arg_typ_pharfile($arg, $cfg, $key)
- {
- try {
- $pharfile = self::cli_arg_typ_file($arg, $cfg, $key);
-
- if (!Phar::loadPhar($pharfile)) {
- self::error("Unable to open phar '$arg'\n");
- }
-
- return $pharfile;
- } catch(Exception $e) {
- self::error("Exception while opening phar '$arg':\n" . $e->getMessage() . "\n");
- }
- }
- // }}}
- // {{{ static function cli_arg_typ_pharurl
- /**
- * Argument type Phar url-like
- *
- * Check the argument as cli_arg_Typ_phar and return its name prefixed
- * with phar://
- *
- * Ex:
- * <code>
- * $arg = 'pharchive.phar/file.php';
- * cli_arg_typ_pharurl($arg)
- * </code>
- *
- * @param string $arg The url-like phar archive to retrieve.
- * @return string The phar file-archive.
- */
- static function cli_arg_typ_pharurl($arg, $cfg, $key)
- {
- return 'phar://' . self::cli_arg_typ_pharfile($arg, $cfg, $key);
- }
- // }}}
- // {{{ static function cli_arg_typ_phar
- /**
- * Cli argument type phar
- *
- * @param string $arg The phar archive to use.
- * @return object new Phar of the passed argument.
- */
- static function cli_arg_typ_phar($arg, $cfg, $key)
- {
- try {
- return new Phar(self::cli_arg_typ_pharfile($arg, $cfg, $key));
- } catch(Exception $e) {
- self::error("Exception while opening phar '$argv':\n" . $e->getMessage() . "\n");
- }
- }
- // }}}
- // {{{ static function cli_arg_typ_entry
- /**
- * Argument type Entry name
- *
- * @param string $arg The argument (the entry)
- * @return string $arg The entry itself.
- */
- static function cli_arg_typ_entry($arg, $cfg, $key)
- {
- // no further check atm, maybe check for no '/' at beginning
- return $arg;
- }
- // }}}
- // {{{ static function cli_arg_typ_compalg
- /**
- * Argument type compression algorithm
- *
- * @param string $arg The phar selection
- * @param string $cfg The config option.
- * @param string $key The key information.
- * @return string $arg The selected algorithm
- */
- static function cli_arg_typ_compalg($arg, $cfg, $key)
- {
- $arg = self::cli_arg_typ_select($arg, $cfg, $key);
-
- switch($arg) {
- case 'auto':
- if (extension_loaded('zlib')) {
- $arg = 'gz';
- } elseif (extension_loaded('bz2')) {
- $arg = 'bz2';
- } else {
- $arg = '0';
- }
- break;
- }
- return $arg;
- }
- // }}}
- // {{{ static function cli_cmd_inf_pack
- /**
- * Information pack
- *
- * @return string A description about packing files into a Phar archive.
- */
- static function cli_cmd_inf_pack()
- {
- return "Pack files into a PHAR archive.\n" .
- "When using -s <stub>, then the stub file is being " .
- "excluded from the list of input files/dirs." .
- "To create an archive that contains PEAR class PHP_Archiave " .
- "then point -p argument to PHP/Archive.php.\n";
- }
- // }}}
- // {{{ static function cli_cmd_arg_pack
- /**
- * Pack a new phar infos
- *
- * @return array $args The arguments for a new Phar archive.
- */
- static function cli_cmd_arg_pack()
- {
- $args = self::phar_args('acFhilpsx', 'pharnew');
-
- $args[''] = array(
- 'typ' => 'any',
- 'val' => NULL,
- 'required' => 1,
- '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.',
-
- );
-
- return $args;
- }
- // }}}
- // {{{ function cli_cmd_run_pack
- /**
- * Pack a new Phar
- *
- * This function will try to pack a new Phar archive.
- *
- * @see Exit to make sure that we are done.
- */
- public function cli_cmd_run_pack()
- {
- if (ini_get('phar.readonly')) {
- self::error("Creating phar files is disabled by ini setting 'phar.readonly'.\n");
- }
-
- if (!Phar::canWrite()) {
- self::error("Creating phar files is disabled, Phar::canWrite() returned false.\n");
- }
-
- $alias = $this->args['a']['val'];
- $archive = $this->args['f']['val'];
- $hash = $this->args['h']['val'];
- $regex = $this->args['i']['val'];
- $level = $this->args['l']['val'];
- $loader = $this->args['p']['val'];
- $stub = $this->args['s']['val'];
- $invregex = $this->args['x']['val'];
- $input = $this->args['']['val'];
-
- $phar = new Phar($archive, 0, $alias);
-
- $phar->startBuffering();
-
- if (isset($stub)) {
- if (isset($loader)) {
- $c = file_get_contents($stub);
- $s = '';
-
- if (substr($c, 0, 2) == '#!') {
- $s .= substr($c, 0, strpos($c, "\n") + 1);
- }
-
- $s .= "<?php if (!class_exists('PHP_Archive')) {\n?>";
- $s .= file_get_contents($loader);
- $s .= "<?php\n";
- $s .= "}\n";
- $s .= "if (!in_array('phar', stream_get_wrappers())) {\n\tstream_wrapper_register('phar', 'PHP_Archive');\n}\n";
- $s .= "if (!class_exists('Phar',0)) {\n";
- $s .= "\tinclude 'phar://'.__FILE__.'/phar.inc';\n";
- $s .= "}\n";
- $s .= '?>';
-
- if (substr($c,0,1) == '#') {
- $s.= substr($c,strpos($c, "\n")+1);
- }
-
- $phar->setStub($s);
- } else {
- $phar->setStub(file_get_contents($stub));
- }
- $stub = new SplFileInfo($stub);
- }
-
- if (!is_array($input)) {
- $this->phar_add($phar, $level, $input, $regex, $invregex, $stub, NULL, isset($loader));
- } else {
- foreach($input as $i) {
- $this->phar_add($phar, $level, $i, $regex, $invregex, $stub, NULL, isset($loader));
- }
- }
-
- if (isset($loader)) {
- if (substr(__FILE__, -15) == 'pharcommand.inc') {
- self::phar_add_file($phar, 0, 'phar.inc', 'phar://'.__FILE__.'/phar.inc', NULL);
- } else {
- self::phar_add_file($phar, 0, 'phar.inc', dirname(__FILE__).'/phar/phar.inc', NULL);
- }
- }
-
- switch($this->args['c']['val']) {
- case 'gz':
- case 'gzip':
- $phar->compressAllFilesGZ();
- break;
- case 'bz2':
- case 'bzip2':
- $phar->compressAllFilesBZIP2();
- break;
- default:
- $phar->uncompressAllFiles();
- break;
- }
-
- if ($hash) {
- $phar->setSignatureAlgorithm($hash);
- }
-
- $phar->stopBuffering();
- exit(0);
- }
- // }}}
- // {{{ static function phar_add
- /**
- * Add files to a phar archive.
- *
- * This function will take a directory and iterate through
- * it and get the files to insert into the Phar archive.
- *
- * @param Phar $phar The phar object.
- * @param string $input The input directory
- * @param string $regex The regex use in RegexIterator.
- * @param string $invregex The InvertedRegexIterator expression.
- * @param SplFileInfo $stub Stub file object
- * @param mixed $compress Compression algorithm or NULL
- * @param boolean $noloader Whether to prevent adding the loader
- */
- static function phar_add(Phar $phar, $level, $input, $regex, $invregex, SplFileInfo $stub = NULL, $compress = NULL, $noloader = false)
- {
- if ($input && is_file($input) && !is_dir($input)) {
- return self::phar_add_file($phar, $level, $input, $input, $compress);
- }
- $dir = new RecursiveDirectoryIterator($input);
- $dir = new RecursiveIteratorIterator($dir);
-
- if (isset($regex)) {
- $dir = new RegexIterator($dir, $regex);
- }
-
- if (isset($invregex)) {
- $dir = new InvertedRegexIterator($dir, $invregex);
- }
-
- try {
- foreach($dir as $file) {
- if (empty($stub) || $file->getRealPath() != $stub->getRealPath()) {
- self::phar_add_file($phar, $level, $dir->getSubPathName(), $file, $compress, $noloader);
- }
- }
- } catch(Excpetion $e) {
- self::error("Unable to complete operation on file '$file'\n" . $e->getMessage() . "\n");
- }
- }
- // }}}
- // {{{ static function phar_add_file
- /**
- * Add a phar file
- *
- * This function adds a file to a phar archive.
- *
- * @param Phar $phar The phar object
- * @param string $level The level of the file.
- * @param string $entry The entry point
- * @param string $file The file to add to the archive
- * @param string $compress The compression scheme for the file.
- * @param boolean $noloader Whether to prevent adding the loader
- */
- static function phar_add_file(Phar $phar, $level, $entry, $file, $compress, $noloader = false)
- {
- $entry = str_replace('//', '/', $entry);
- while($level-- > 0 && ($p = strpos($entry, '/')) !== false) {
- $entry = substr($entry, $p+1);
- }
-
- if ($noloader && $entry == 'phar.inc') {
- return;
- }
-
- echo "$entry\n";
-
- $phar[$entry] = file_get_contents($file);
- switch($compress) {
- case 'gz':
- case 'gzip':
- $phar[$entry]->setCompressedGZ();
- break;
- case 'bz2':
- case 'bzip2':
- $phar[$entry]->setCompressedBZIP2();
- break;
- default:
- break;
- }
- }
- // }}}
- // {{{ public function phar_dir_echo
- /**
- * Echo directory
- *
- * @param string $pn
- * @param unknown_type $f
- */
- public function phar_dir_echo($pn, $f)
- {
- echo "$f\n";
- }
- // }}}
- // {{{ public function phar_dir_operation
- /**
- * Directory operations
- *
- * Phar directory operations.
- *
- * @param RecursiveIteratorIterator $dir The recursiveIteratorIterator object.
- * @param string $func Function to call on the iterations
- * @param array $args Function arguments.
- */
- public function phar_dir_operation(RecursiveIteratorIterator $dir, $func, array $args = array())
- {
- $regex = $this->args['i']['val'];
- $invregex= $this->args['x']['val'];
-
- if (isset($regex)) {
- $dir = new RegexIterator($dir, $regex);
- }
-
- if (isset($invregex)) {
- $dir = new InvertedRegexIterator($dir, $invregex);
- }
-
- foreach($dir as $pn => $f) {
- call_user_func($func, $pn, $f, $args);
- }
- }
- // {{{ static function cli_cmd_inf_list
- /**
- * Cli Command Info List
- *
- * @return string What inf does
- */
- static function cli_cmd_inf_list()
- {
- return "List contents of a PHAR archive.";
- }
- // }}}
- // {{{ static function cli_cmd_arg_list
- /**
- * Cli Command Argument List
- *
- * @return arguments list
- */
- static function cli_cmd_arg_list()
- {
- return self::phar_args('Fix', 'pharurl');
- }
- // }}}
- // {{{ public function cli_cmd_run_list
- /**
- * Cli Command Run List
- *
- * @see $this->phar_dir_operation
- */
- public function cli_cmd_run_list()
- {
- $this->phar_dir_operation(
- new DirectoryTreeIterator(
- $this->args['f']['val']),
- array($this, 'phar_dir_echo')
- );
- }
- // }}}
- // {{{ static function cli_command_inf_tree
- /**
- * Cli Command Inf Tree
- *
- * @return string The description of a directory tree for a Phar archive.
- */
- static function cli_cmd_inf_tree()
- {
- return "Get a directory tree for a PHAR archive.";
- }
- // }}}
- // {{{ static function cli_cmd_arg_tree
- /**
- * Cli Command Argument Tree
- *
- * @return string Arguments in URL format.
- */
- static function cli_cmd_arg_tree()
- {
- return self::phar_args('Fix', 'pharurl');
- }
- // }}}
- // {{{ public function cli_cmd_run_tree
- /**
- * Cli Command Run Tree
- *
- * Set the phar_dir_operation with a directorygraphiterator.
- *
- * @see DirectoryGraphIterator
- * @see $this->phar_dir_operation
- *
- */
- public function cli_cmd_run_tree()
- {
- $this->phar_dir_operation(
- new DirectoryGraphIterator(
- $this->args['f']['val']),
- array($this, 'phar_dir_echo')
- );
- }
- // }}}
- // {{{ cli_cmd_inf_extract
- /**
- * Cli Command Inf Extract
- *
- * @return string The description of the command extra to a directory.
- */
- static function cli_cmd_inf_extract()
- {
- return "Extract a PHAR package to a directory.";
- }
- // }}}
- // {{{ static function cli_cmd_arg_extract
- /**
- * Cli Command Arguments Extract
- *
- * The arguments for the extract function.
- *
- * @return array The arguments for the extraction.
- */
- static function cli_cmd_arg_extract()
- {
- $args = self::phar_args('Fix', 'phar');
-
- $args[''] = array(
- 'type' => 'dir',
- 'val' => '.',
- 'inf' => ' Directory to extract to (defaults to \'.\').',
- );
-
- return $args;
- }
- // }}}
- // {{{ public function cli_cmd_run_extract
- /**
- * Run Extract
- *
- * Run the extraction of a phar Archive.
- *
- * @see $this->phar_dir_operation
- */
- public function cli_cmd_run_extract()
- {
- $dir = $this->args['']['val'];
-
- if (is_array($dir)) {
- if (count($dir) != 1) {
- self::error("Only one target directory allowed.\n");
- } else {
- $dir = $dir[0];
- }
- }
-
- $phar = $args['f']['val'];
- $base = $phar->getPathname();
- $bend = strpos($base, '.phar');
- $bend = strpos($base, '/', $bend);
- $base = substr($base, 0, $bend + 1);
- $blen = strlen($base);
-
- $this->phar_dir_operation(
- new RecursiveIteratorIterator($phar),
- array($this, 'phar_dir_extract'),
- array($blen, $dir)
- );
- }
- // }}}
- // {{{ public function phar_dir_extract
- /**
- * Extract to a directory
- *
- * This function will extract the content of a Phar
- * to a directory and create new files and directories
- * depending on the permissions on that folder.
- *
- * @param string $pn
- * @param string $f The file name
- * @param array $args The directory and Blen informations
- */
- public function phar_dir_extract($pn, $f, $args)
- {
- $blen = $args[0];
- $dir = $args[1];
- $sub = substr($pn, $blen);
- $target = $dir . '/' . $sub;
-
- if (!file_exists(dirname($target))) {
- if (!is_writable(dirname($target))) {
- self::error("Operation could not be completed\n");
- }
-
- mkdir(dirname($target));
- }
-
- echo "$sub";
-
- if (!@copy($f, $target)) {
- echo " ...error\n";
- } else {
- echo " ...ok\n";
- }
- }
- // }}}
- // {{{ static function cli_cmd_inf_delete
- /**
- * Delete an entry from a phar information.
- *
- * @return string The information
- */
- static function cli_cmd_inf_delete()
- {
- return 'Delete entry from a PHAR archive';
- }
- // }}}
- // {{{ static function cli_cmd_arg_delete
- /**
- * The cli command argument for deleting.
- *
- * @return array informations about the arguments to use.
- */
- static function cli_cmd_arg_delete()
- {
- return self::phar_args('FE', 'phar');
- }
- // }}}
- // {{{ public function cli_cmd_run_delete
- /**
- * Deleting execution
- *
- * Execute the deleting of the file from the phar archive.
- */
- public function cli_cmd_run_delete()
- {
- $phar = $this->args['f']['val'];
- $entry = $this->args['e']['val'];
-
- $phar->startBuffering();
- unset($phar[$entry]);
- $phar->stopBuffering();
- }
- // }}}
- // {{{ static function cli_cmd_inf_add
- /**
- * Client comment add file information
- *
- * @return string The description of the feature
- */
- static function cli_cmd_inf_add()
- {
- return "Add entries to a PHAR package.";
- }
- // }}}
- // {{{ static function cli_cmd_arg_add
- /**
- * Add a file arguments
- */
- static function cli_cmd_arg_add()
- {
- $args = self::phar_args('acFilx', 'phar');
- $args[''] = array(
- 'type' => 'any',
- 'val' => NULL,
- 'required' => 1,
- '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.',
- );
- return $args;
- }
- // }}}
- // {{{ public functio cli_cmd_run_add
- /**
- * Add a file
- *
- * Run the action of adding a file to
- * a phar archive.
- */
- public function cli_cmd_run_add()
- {
- $compress= $this->args['c']['val'];
- $phar = $this->args['f']['val'];
- $regex = $this->args['i']['val'];
- $level = $this->args['l']['val'];
- $invregex= $this->args['x']['val'];
- $input = $this->args['']['val'];
-
- $phar->startBuffering();
-
- if (!is_array($input)) {
- $this->phar_add($phar, $level, $input, $regex, $invregex, NULL, $compress);
- } else {
- foreach($input as $i) {
- $this->phar_add($phar, $level, $i, $regex, $invregex, NULL, $compress);
- }
- }
- $phar->stopBuffering();
- exit(0);
- }
- // }}}
- // {{{ public function cli_cmd_inf_stub_set
- /**
- * Set the stup of a phar file.
- *
- * @return string The stub set description.
- */
- public function cli_cmd_inf_stub_set()
- {
- return "Set the stub of a PHAR file. " .
- "If no input file is specified as stub then stdin is being used.";
- }
- // }}}
- // {{{ public function cli_cmd_arg_stub_set
- /**
- * Set the argument stub
- *
- * @return string arguments for a stub
- */
- public function cli_cmd_arg_stub_set()
- {
- $args = self::phar_args('Fs', 'phar');
- $args['s']['val'] = 'php://stdin';
- return $args;
- }
- // }}}
- // {{{ public function cli_cmd_run_stub_set
- /**
- * Cli Command run stub set
- *
- * @see $phar->setStub()
- */
- public function cli_cmd_run_stub_set()
- {
- $phar = $this->args['f']['val'];
- $stub = $this->args['s']['val'];
-
- $phar->setStub(file_get_contents($stub));
- }
- // }}}
- // {{{ public function cli_cmd_inf_stub_get
- /**
- * Get the command stub infos.
- *
- * @return string a description of the stub of a Phar file.
- */
- public function cli_cmd_inf_stub_get()
- {
- return "Get the stub of a PHAR file. " .
- "If no output file is specified as stub then stdout is being used.";
- }
- // }}}
- // {{{ public function cli_cmd_arg_stub_get
- /**
- * Get the argument stub
- *
- * @return array $args The arguments passed to the stub.
- */
- public function cli_cmd_arg_stub_get()
- {
- $args = self::phar_args('Fs', 'phar');
- $args['s']['val'] = 'php://stdin';
- return $args;
- }
- // }}}
- // {{{ public function cli_cmd_run_stub_get
- /**
- * Cli Command Run Stub
- *
- * Get arguments and store them into a stub.
- *
- * @param arguments $args
- * @see $this->args
- */
- public function cli_cmd_run_stub_get($args)
- {
- $phar = $this->args['f']['val'];
- $stub = $this->args['s']['val'];
-
- file_put_contents($stub, $phar->getStub());
- }
- // }}}
- // {{{ public function cli_cmd_inf_compress
- /**
- * Cli Command Inf Compress
- *
- * Cli Command compress informations
- *
- * @return string A description of the command.
- */
- public function cli_cmd_inf_compress()
- {
- return "Compress or uncompress all files or a selected entry.";
- }
- // }}}
- // {{{ public function cli_cmd_arg_cmpress
- /**
- * Cli Command Arg Compress
- *
- * @return array The arguments for compress
- */
- public function cli_cmd_arg_compress()
- {
- return self::phar_args('FCe', 'phar');
- }
- // }}}
- // {{{ public function cli_cmd_run_compress
- /**
- * Cli Command Run Compress
- *
- * @see $this->args
- */
- public function cli_cmd_run_compress()
- {
- $phar = $this->args['f']['val'];
- $entry = $this->args['e']['val'];
-
- switch($this->args['c']['val']) {
- case 'gz':
- case 'gzip':
- if (isset($entry)) {
- $phar[$entry]->setCompressedGZ();
- } else {
- $phar->compressAllFilesGZ();
- }
- break;
- case 'bz2':
- case 'bzip2':
- if (isset($entry)) {
- $phar[$entry]->setCompressedBZIP2();
- } else {
- $phar->compressAllFilesBZIP2();
- }
- break;
- default:
- if (isset($entry)) {
- $phar[$entry]->setUncompressed();
- } else {
- $phar->uncompressAllFiles();
- }
- break;
- }
- }
- // }}}
- // {{{ public function cli_cmd_inf_sign
- /**
- * Cli Command Info Signature
- *
- * @return string A description of the signature arguments.
- */
- public function cli_cmd_inf_sign()
- {
- return "Set signature hash algorithm.";
- }
- // }}}
- // {{{ public function cli_cmd_arg_sign
- /**
- * Cli Command Argument Sign
- *
- * @return array Arguments for Signature
- */
- public function cli_cmd_arg_sign()
- {
- return self::phar_args('FH', 'phar');
- }
- // }}}
- // {{{ public function cli_cmd_run_sign
- /**
- * Cli Command Run Signature
- *
- * @see $phar->setSignaturealgorithm
- */
- public function cli_cmd_run_sign()
- {
- $phar = $this->args['f']['val'];
- $hash = $this->args['h']['val'];
-
- $phar->setSignatureAlgorithm($hash);
- }
- // }}}
- // {{{ public function cli_cmd_inf_meta_set
- /**
- * Cli Command Inf Meta Set
- *
- * @return string A description
- */
- public function cli_cmd_inf_meta_set()
- {
- return "Set meta data of a PHAR entry or a PHAR package using serialized input. " .
- "If no input file is specified for meta data then stdin is being used." .
- "You can also specify a particular index using -k. In that case the metadata is " .
- "expected to be an array and the value of the given index is being set. If " .
- "the metadata is not present or empty a new array will be created. If the " .
- "metadata is present and a flat value then the return value is 1. Also using -k " .
- "the input is been taken directly rather then being serialized.";
- }
- // }}}
- // {{{ public function cli_cmd_arg_meta_set
- /**
- * Cli Command Argument Meta Set
- *
- * @return array The arguments for meta set
- */
- public function cli_cmd_arg_meta_set()
- {
- return self::phar_args('FekM', 'phar');
- }
- // }}}
- // {{{ public function cli_cmd_run_met_set
- /**
- * Cli Command Run Metaset
- *
- * @see $phar->startBuffering
- * @see $phar->setMetadata
- * @see $phar->stopBuffering
- */
- public function cli_cmd_run_meta_set()
- {
- $phar = $this->args['f']['val'];
- $entry = $this->args['e']['val'];
- $index = $this->args['k']['val'];
- $meta = $this->args['m']['val'];
-
- $phar->startBuffering();
-
- if (isset($index)) {
- if (isset($entry)) {
- if ($phar[$entry]->hasMetadata()) {
- $old = $phar[$entry]->getMetadata();
- } else {
- $old = array();
- }
- } else {
- if ($phar->hasMetadata()) {
- $old = $phar->getMetadata();
- } else {
- $old = array();
- }
- }
-
- if (!is_array($old)) {
- self::error('Metadata is a flat value while an index operation was issued.');
- }
-
- $old[$index] = $meta;
- $meta = $old;
- } else {
- $meta = unserialize($meta);
- }
-
- if (isset($entry)) {
- $phar[$entry]->setMetadata($meta);
- } else {
- $phar->setMetadata($meta);
- }
- $phar->stopBuffering();
- }
- // }}}
- // {{{ public function cli_cmd_inf_met_get
- /**
- * Cli Command Inf Metaget
- *
- * @return string A description of the metaget arguments
- */
- public function cli_cmd_inf_meta_get()
- {
- return "Get meta information of a PHAR entry or a PHAR package in serialized from. " .
- "If no output file is specified for meta data then stdout is being used.\n" .
- "You can also specify a particular index using -k. In that case the metadata is " .
- "expected to be an array and the value of the given index is returned using echo " .
- "rather than using serialize. If that index does not exist or no meta data is " .
- "present then the return value is 1.";
- }
- // }}}
- // {{{ public function cli_cmd_arg_meta_get
- /**
- * Cli Command arg metaget
- *
- * @return array The arguments for meta get.
- */
- public function cli_cmd_arg_meta_get()
- {
- return self::phar_args('Fek', 'phar');
- }
- // }}}
- // {{{ public function cli_cmd_run_meta_get
- /**
- * Cli Command Run Metaget
- *
- * @see $this->args
- * @see $phar[$x]->hasMetadata()
- * @see $phar->getMetadata()
- */
- public function cli_cmd_run_meta_get()
- {
- $phar = $this->args['f']['val'];
- $entry = $this->args['e']['val'];
- $index = $this->args['k']['val'];
-
- if (isset($entry)) {
- if (!$phar[$entry]->hasMetadata()) {
- exit(1);
- }
- echo serialize($phar[$entry]->getMetadata());
- } else {
- if (!$phar->hasMetadata()) {
- exit(1);
- }
- $meta = $phar->getMetadata();
- }
-
- if (isset($index)) {
- if (isset($index)) {
- if (isset($meta[$index])) {
- echo $meta[$index];
- exit(0);
- } else {
- exit(1);
- }
- } else {
- echo serialize($meta);
- }
- }
- }
- // }}}
- // {{{ public function cli_cmd_inf_meta_del
- /**
- * Cli Command Inf Metadel
- *
- * @return string A description of the metadel function
- */
- public function cli_cmd_inf_meta_del()
- {
- return "Delete meta information of a PHAR entry or a PHAR package.\n" .
- "If -k is given then the metadata is expected to be an array " .
- "and the given index is being deleted.\n" .
- "If something was deleted the return value is 0 otherwise it is 1.";
- }
- // }}}
- // {{{ public function cli_cmd_arg_meta_del
- /**
- * CliC ommand Arg Metadelete
- *
- * @return array The arguments for metadel
- */
- public function cli_cmd_arg_meta_del()
- {
- return self::phar_args('Fek', 'phar');
- }
- // }}}
- // {{{ public function cli_cmd_run_meta_del
- /**
- * Cli Command Run MetaDel
- *
- * @see $phar[$x]->delMetadata()
- * @see $phar->delMetadata()
- */
- public function cli_cmd_run_meta_del()
- {
- $phar = $this->args['f']['val'];
- $entry = $this->args['e']['val'];
- $index = $this->args['k']['val'];
-
- if (isset($entry)) {
- if (isset($index)) {
- if (!$phar[$entry]->hasMetadata()) {
- exit(1);
- }
- $meta = $phar[$entry]->getMetadata();
-
- // @todo add error message here.
- if (!is_array($meta)) {
- exit(1);
- }
-
- unset($meta[$index]);
- $phar[$entry]->setMetadata($meta);
- } else {
- exit($phar[$entry]->delMetadata() ? 0 : 1);
- }
- } else {
- if (isset($index)) {
- if (!$phar->hasMetadata()) {
- exit(1);
- }
-
- $meta = $phar->getMetadata();
-
- // @todo Add error message
- if (!is_array($meta)) {
- exit(1);
- }
-
- unset($meta[$index]);
- $phar->setMetadata($meta);
- } else {
- exit($phar->delMetadata() ? 0 : 1);
- }
- }
- }
- // }}}
- // {{{ public function cli_cmd_inf_info
- /**
- * CLi Command Inf Info
- *
- * @return string A description about the info commands.
- */
- public function cli_cmd_inf_info()
- {
- return "Get information about a PHAR package.\n" .
- "By using -k it is possible to return a single value.";
- }
- // }}}
- // {{{ public function cli_cmd_arg_info
- /**
- * Cli Command Arg Infos
- *
- * @return array The arguments for info command.
- */
- public function cli_cmd_arg_info()
- {
- return self::phar_args('Fk', 'phar');
- }
- // }}}
- // {{{ public function cli_cmd_run_info
- /**
- * Cli Command Run Info
- *
- * @param args $args
- */
- public function cli_cmd_run_info()
- {
- $phar = $this->args['f']['val'];
- $index = $this->args['k']['val'];
-
- $hash = $phar->getSignature();
- $infos = array();
-
- if ($phar->getAlias()) {
- $infos['Alias'] = $phar->getAlias();
- }
-
- if (!$hash) {
- $infos['Hash-type'] = 'NONE';
- } else {
- $infos['Hash-type'] = $hash['hash_type'];
- $infos['Hash'] = $hash['hash'];
- }
-
- $csize = 0;
- $usize = 0;
- $count = 0;
- $ccount = 0;
- $ucount = 0;
- $mcount = 0;
- $compalg = array('GZ'=>0, 'BZ2'=>0);
-
- foreach(new RecursiveIteratorIterator($phar) as $ent) {
- $count++;
- if ($ent->isCompressed()) {
- $ccount++;
- $csize += $ent->getCompressedSize();
- if ($ent->isCompressedGZ()) {
- $compalg['GZ']++;
- } elseif ($ent->isCompressedBZIP2()) {
- $compalg['BZ2']++;
- }
- } else {
- $ucount++;
- $csize += $ent->getSize();
- }
-
- $usize += $ent->getSize();
-
- if ($ent->hasMetadata()) {
- $mcount++;
- }
- }
-
- $infos['Entries'] = $count;
- $infos['Uncompressed-files'] = $ucount;
- $infos['Compressed-files'] = $ccount;
- $infos['Compressed-gz'] = $compalg['GZ'];
- $infos['Compressed-bz2'] = $compalg['BZ2'];
- $infos['Uncompressed-size'] = $usize;
- $infos['Compressed-size'] = $csize;
- $infos['Compression-ratio'] = sprintf('%.3g%%', $usize ? ($csize * 100) / $usize : 100);
- $infos['Metadata-global'] = $phar->hasMetadata() * 1;
- $infos['Metadata-files'] = $mcount;
- $infos['Stub-size'] = strlen($phar->getStub());
-
- if (isset($index)) {
- if (!isset($infos[$index])) {
- self::error("Requested value does not exist.\n");
- }
-
- echo $infos[$index];
- exit(0);
- }
-
- $l = 0;
- foreach($infos as $which => $val) {
- $l = max(strlen($which), $l);
- }
-
- foreach($infos as $which => $val) {
- echo $which . ':' . str_repeat(' ', $l + 1 - strlen($which)) . $val . "\n";
- }
- }
- // }}}
-}
-// }}}
-
-}
-
-
-new PharCommand($argc, $argv);