+ * require_once 'phar://PEAR.phar/PEAR/Installer.php';
+ *
+ * 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");
+ return false;
+ }
+ if (self::_fileExists($archive, $_GET['viewsource'])) {
+ $source = highlight_file('phar://go-pear.phar/' .
+ $_GET['viewsource'], true);
+ header('Content-Type: text/html');
+ header('Content-Length: ' . strlen($source));
+ echo 'Try ', + 'This link
'; + return false; + } + } + + 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'])) { + return self::viewSource($archive, $_GET['viewsource']); + } + if (isset($_GET['introspect'])) { + return self::introspect($archive, $_GET['introspect']); + } + $subpath = '/' . $initfile; + } + if (!self::_fileExists($archive, substr($subpath, 1))) { + header("HTTP/1.0 404 Not Found"); + return false; + } + foreach (self::$deny as $pattern) { + if (preg_match($pattern, $subpath)) { + header("HTTP/1.0 404 Not Found"); + return false; + } + } + $inf = pathinfo(basename($subpath)); + if (!isset($inf['extension'])) { + header('Content-Type: text/plain'); + header('Content-Length: ' . + self::_filesize($archive, substr($subpath, 1))); + readfile('phar://go-pear.phar' . $subpath); + return false; + } + if (isset(self::$defaultphp[$inf['extension']])) { + include 'phar://go-pear.phar' . $subpath; + return false; + } + if (isset(self::$defaultmimes[$inf['extension']])) { + header('Content-Type: ' . self::$defaultmimes[$inf['extension']]); + header('Content-Length: ' . + self::_filesize($archive, substr($subpath, 1))); + readfile('phar://go-pear.phar' . $subpath); + return false; + } + if (isset(self::$defaultphps[$inf['extension']])) { + header('Content-Type: text/html'); + $c = highlight_file('phar://go-pear.phar' . $subpath, true); + header('Content-Length: ' . strlen($c)); + echo $c; + return false; + } + header('Content-Type: text/plain'); + header('Content-Length: ' . + self::_filesize($archive, substr($subpath, 1))); + readfile('phar://go-pear.phar' . $subpath); + } + } + + /** + * 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 (!strlen($buffer)) { + return $pos; + } + 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 (!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 43508 + */ + public static final function mapPhar($alias = NULL, $dataoffset = NULL) + { + try { + $trace = debug_backtrace(); + $file = $trace[0]['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'); + } + $file = realpath($file); + if (!isset($dataoffset)) { + $dataoffset = constant('__COMPILER_HALT_OFFSET'.'__'); + $fp = fopen($file, 'rb'); + fseek($fp, $dataoffset, SEEK_SET); + $dataoffset = $dataoffset + self::_endOfStubLength(fread($fp, 5)); + fclose($fp); + } + + self::_mapPhar($file, $dataoffset); + } 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[1] & 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] + & 0xffffffff); + 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 = preg_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])) { + if ($path[strlen($path)-1] == '/') { + // directory + if (!$allowdirs) { + return 'Error: "' . $path . '" is a directory in phar "' . $this->_basename . '"'; + } + $this->_setCurrentFile($path, true); + } else { + $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, $dir = false) + { + if ($dir) { + $this->currentStat = array( + 2 => 040777, // directory mode, readable by all, writeable by none + 4 => 0, // uid + 5 => 0, // gid + 7 => 0, // size + 9 => self::$_manifest[$this->_archiveName][$path][1], // creation time + ); + $this->internalFileLength = 0; + $this->isDir = true; + } else { + $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->internalFileLength = self::$_manifest[$this->_archiveName][$path][2]; + $this->isDir = false; + } + $this->currentFilename = $path; + // 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) & 0xffffffff)) { + 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]; + break; + 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 ($fname == '/' || $fname[strlen($fname)-1] == '/') { + continue; // empty directory + } + 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(); + 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 static 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'; + } + if (extension_loaded('openssl')) { + $ret[] = 'OpenSSL'; + } + return $ret; + } +}} +if (!class_exists('Phar')) { + PHP_Archive::mapPhar(null, 43508 ); +} else { + try { + Phar::mapPhar(); + } catch (Exception $e) { + echo $e->getMessage(); + } +} +if (class_exists('PHP_Archive') && !in_array('phar', stream_get_wrappers())) { + stream_wrapper_register('phar', 'PHP_Archive'); +} + +@ini_set('memory_limit', -1); +if (extension_loaded('phar')) {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']); + $mimetypes = 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', +); + $phpfiles = array ( + 'php' => true, +); + $phpsfiles = array ( + 'phps' => true, +); + $deny = array ( + 0 => '/.+\\.inc$/', +); + $subpath = str_replace('/' . basename($archive), '', $uri['path']); + if (!$subpath || $subpath == '/') { + $subpath = '/PEAR.php'; + } + if ($subpath[0] != '/') { + $subpath = '/' . $subpath; + } + if (!@file_exists('phar://' . $archive . $subpath)) { + header("HTTP/1.0 404 Not Found"); + exit; + } + + foreach ($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: ' . filesize('phar://' . $archive . $subpath)); + readfile('phar://' . $archive . $subpath); + exit; + } + if (isset($phpfiles[$inf['extension']])) { + include 'phar://' . $archive . '/' . $subpath; + exit; + } + if (isset($mimetypes[$inf['extension']])) { + header('Content-Type: ' . $mimetypes[$inf['extension']]); + header('Content-Length: ' . filesize('phar://' . $archive . $subpath)); + readfile('phar://' . $archive . $subpath); + exit; + } + if (isset($phpsfiles[$inf['extension']])) { + header('Content-Type: text/html'); + $c = highlight_file('phar://' . $archive . $subpath, true); + header('Content-Length: ' . strlen($c)); + echo $c; + exit; + } + header('Content-Type: text/plain'); + header('Content-Length: ' . filesize('phar://' . $archive . '/' . $subpath)); + readfile('phar://' . $archive . '/' . $subpath); + exit; +}} else {if (!empty($_SERVER['REQUEST_URI'])) {PHP_Archive::webFrontController('PEAR.php');exit;}} + + + +require_once 'phar://go-pear.phar/index.php'; +__HALT_COMPILER();= E go-pear.phar Archive/Tar.php@ ."V@ e m Console/Getopt.php}4 ."V}4 eom index.php ."V A#m OS/Guess.phps) ."Vs) m PEAR.php ."V Gm PEAR/ChannelFile.phpJ ."VJ m PEAR/ChannelFile/Parser.php ."V ʄvm PEAR/Command.php0 ."V0 ^9m PEAR/Command/Common.php6 ."V6 m PEAR/Command/Install.php ."V m PEAR/Command/Install.xml~! ."V~! 2Vm PEAR/Common.phpGh ."VGh iTm PEAR/Config.php ."V km PEAR/Dependency2.phpz ."Vz `m PEAR/DependencyDB.php*^ ."V*^ K-m PEAR/Downloader.php ."V u*m PEAR/Downloader/Package.php3* ."V3* %m PEAR/ErrorStack.php ."V Rfm PEAR/Frontend.php + ."V + 1)m PEAR/Frontend/CLI.phped ."Ved m + PEAR/go-pear-tarballs/Archive_Tar-1.4.0.tar ."V ihm . PEAR/go-pear-tarballs/Console_Getopt-1.4.1.tar t ."V t Hm % PEAR/go-pear-tarballs/PEAR-1.10.1.tar ( ."V ( %.m 0 PEAR/go-pear-tarballs/Structures_Graph-1.1.1.tar 6 ."V 6 jm ( PEAR/go-pear-tarballs/XML_Util-1.3.0.tar ."V &jHFm PEAR/Installer.phpR ."VR # lm PEAR/Installer/Role.php ."V Illm PEAR/Installer/Role/Common.phpF ."VF m PEAR/Installer/Role/Data.php ."V z(m PEAR/Installer/Role/Data.xml ."V fszm PEAR/Installer/Role/Doc.php ."V 㔺mm PEAR/Installer/Role/Doc.xml ."V h&P*m PEAR/Installer/Role/Php.php ."V *1m PEAR/Installer/Role/Php.xml ."V zqm PEAR/Installer/Role/Script.php ."V J0Hm PEAR/Installer/Role/Script.xml ."V @vm PEAR/Installer/Role/Test.php ."V m PEAR/Installer/Role/Test.xml ."V B] m PEAR/PackageFile.phpZ> ."VZ> nsm ! PEAR/PackageFile/Generator/v1.php ."V WYJm ! PEAR/PackageFile/Generator/v2.php ."V M +-m PEAR/PackageFile/Parser/v1.php@ ."V@ Юm PEAR/PackageFile/Parser/v2.phpv ."Vv jm PEAR/PackageFile/v1.php ."V ى3m PEAR/PackageFile/v2.php ."V m ! PEAR/PackageFile/v2/Validator.phpzL ."VzL m PEAR/Registry.phpq) ."Vq) @ m PEAR/REST.php"F ."V"F @ m PEAR/REST/10.php ."V C;m PEAR/Start.php9 ."V9 3m PEAR/Start/CLI.phpHS ."VHS >iZ m PEAR/Task/Common.php7 ."V7 4[m PEAR/Task/Postinstallscript.phpG9 ."VG9 H>m " PEAR/Task/Postinstallscript/rw.php; ."V;