Advertisement
Guest User

go-pear.phar

a guest
Feb 11th, 2013
467
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 42.53 KB | None | 0 0
  1. <?php
  2. error_reporting(1803);
  3. if (function_exists('mb_internal_encoding')) {
  4.     mb_internal_encoding('ASCII');
  5. }
  6. if (!class_exists('PHP_Archive')) {/**
  7.  * PHP_Archive Class (implements .phar)
  8.  *
  9.  * @package PHP_Archive
  10.  * @category PHP
  11.  */
  12. /**
  13.  * PHP_Archive Class (implements .phar)
  14.  *
  15.  * PHAR files a singular archive from which an entire application can run.
  16.  * To use it, simply package it using {@see PHP_Archive_Creator} and use phar://
  17.  * URIs to your includes. i.e. require_once 'phar://config.php' will include config.php
  18.  * from the root of the PHAR file.
  19.  *
  20.  * Gz code borrowed from the excellent File_Archive package by Vincent Lascaux.
  21.  *
  22.  * @copyright Copyright David Shafik and Synaptic Media 2004. All rights reserved.
  23.  * @author Davey Shafik <davey@synapticmedia.net>
  24.  * @author Greg Beaver <cellog@php.net>
  25.  * @link http://www.synapticmedia.net Synaptic Media
  26.  * @version Id: Archive.php,v 1.52 2007/09/01 20:28:14 cellog Exp $
  27.  * @package PHP_Archive
  28.  * @category PHP
  29.  */
  30.  
  31. class PHP_Archive
  32. {
  33.     const GZ = 0x00001000;
  34.     const BZ2 = 0x00002000;
  35.     const SIG = 0x00010000;
  36.     const SHA1 = 0x0002;
  37.     const MD5 = 0x0001;
  38.     /**
  39.      * Whether this archive is compressed with zlib
  40.      *
  41.      * @var bool
  42.      */
  43.     private $_compressed;
  44.     /**
  45.      * @var string Real path to the .phar archive
  46.      */
  47.     private $_archiveName = null;
  48.     /**
  49.      * Current file name in the phar
  50.      * @var string
  51.      */
  52.     protected $currentFilename = null;
  53.     /**
  54.      * Length of current file in the phar
  55.      * @var string
  56.      */
  57.     protected $internalFileLength = null;
  58.     /**
  59.      * Current file statistics (size, creation date, etc.)
  60.      * @var string
  61.      */
  62.     protected $currentStat = null;
  63.     /**
  64.      * @var resource|null Pointer to open .phar
  65.      */
  66.     protected $fp = null;
  67.     /**
  68.      * @var int Current Position of the pointer
  69.      */
  70.     protected $position = 0;
  71.  
  72.     /**
  73.      * Map actual realpath of phars to meta-data about the phar
  74.      *
  75.      * Data is indexed by the alias that is used by internal files.  In other
  76.      * words, if a file is included via:
  77.      * <code>
  78.      * require_once 'phar://PEAR.phar/PEAR/Installer.php';
  79.      * </code>
  80.      * then the alias is "PEAR.phar"
  81.      *
  82.      * Information stored is a boolean indicating whether this .phar is compressed
  83.      * with zlib, another for bzip2, phar-specific meta-data, and
  84.      * the precise offset of internal files
  85.      * within the .phar, used with the {@link $_manifest} to load actual file contents
  86.      * @var array
  87.      */
  88.     private static $_pharMapping = array();
  89.     /**
  90.      * Map real file paths to alias used
  91.      *
  92.      * @var array
  93.      */
  94.     private static $_pharFiles = array();
  95.     /**
  96.      * File listing for the .phar
  97.      *
  98.      * The manifest is indexed per phar.
  99.      *
  100.      * Files within the .phar are indexed by their relative path within the
  101.      * .phar.  Each file has this information in its internal array
  102.      *
  103.      * - 0 = uncompressed file size
  104.      * - 1 = timestamp of when file was added to phar
  105.      * - 2 = offset of file within phar relative to internal file's start
  106.      * - 3 = compressed file size (actual size in the phar)
  107.      * @var array
  108.      */
  109.     private static $_manifest = array();
  110.     /**
  111.      * Absolute offset of internal files within the .phar, indexed by absolute
  112.      * path to the .phar
  113.      *
  114.      * @var array
  115.      */
  116.     private static $_fileStart = array();
  117.     /**
  118.      * file name of the phar
  119.      *
  120.      * @var string
  121.      */
  122.     private $_basename;
  123.  
  124.  
  125.     /**
  126.      * Default MIME types used for the web front controller
  127.      *
  128.      * @var array
  129.      */
  130.     public static $defaultmimes = array(
  131.             'aif' => 'audio/x-aiff',
  132.             'aiff' => 'audio/x-aiff',
  133.             'arc' => 'application/octet-stream',
  134.             'arj' => 'application/octet-stream',
  135.             'art' => 'image/x-jg',
  136.             'asf' => 'video/x-ms-asf',
  137.             'asx' => 'video/x-ms-asf',
  138.             'avi' => 'video/avi',
  139.             'bin' => 'application/octet-stream',
  140.             'bm' => 'image/bmp',
  141.             'bmp' => 'image/bmp',
  142.             'bz2' => 'application/x-bzip2',
  143.             'css' => 'text/css',
  144.             'doc' => 'application/msword',
  145.             'dot' => 'application/msword',
  146.             'dv' => 'video/x-dv',
  147.             'dvi' => 'application/x-dvi',
  148.             'eps' => 'application/postscript',
  149.             'exe' => 'application/octet-stream',
  150.             'gif' => 'image/gif',
  151.             'gz' => 'application/x-gzip',
  152.             'gzip' => 'application/x-gzip',
  153.             'htm' => 'text/html',
  154.             'html' => 'text/html',
  155.             'ico' => 'image/x-icon',
  156.             'jpe' => 'image/jpeg',
  157.             'jpg' => 'image/jpeg',
  158.             'jpeg' => 'image/jpeg',
  159.             'js' => 'application/x-javascript',
  160.             'log' => 'text/plain',
  161.             'mid' => 'audio/x-midi',
  162.             'mov' => 'video/quicktime',
  163.             'mp2' => 'audio/mpeg',
  164.             'mp3' => 'audio/mpeg3',
  165.             'mpg' => 'audio/mpeg',
  166.             'pdf' => 'aplication/pdf',
  167.             'png' => 'image/png',
  168.             'rtf' => 'application/rtf',
  169.             'tif' => 'image/tiff',
  170.             'tiff' => 'image/tiff',
  171.             'txt' => 'text/plain',
  172.             'xml' => 'text/xml',
  173.         );
  174.  
  175.     public static $defaultphp = array(
  176.         'php' => true
  177.         );
  178.  
  179.     public static $defaultphps = array(
  180.         'phps' => true
  181.         );
  182.  
  183.     public static $deny = array('/.+\.inc$/');
  184.  
  185.     public static function viewSource($archive, $file)
  186.     {
  187.         // security, idea borrowed from PHK
  188.         if (!file_exists($archive . '.introspect')) {
  189.             header("HTTP/1.0 404 Not Found");
  190.             return false;
  191.         }
  192.         if (self::_fileExists($archive, $_GET['viewsource'])) {
  193.             $source = highlight_file('phar://go-pear.phar/' .
  194.                 $_GET['viewsource'], true);
  195.             header('Content-Type: text/html');
  196.             header('Content-Length: ' . strlen($source));
  197.             echo '<html><head><title>Source of ',
  198.                 htmlspecialchars($_GET['viewsource']), '</title></head>';
  199.             echo '<body><h1>Source of ',
  200.                 htmlspecialchars($_GET['viewsource']), '</h1>';
  201.             if (isset($_GET['introspect'])) {
  202.                 echo '<a href="', htmlspecialchars($_SERVER['PHP_SELF']),
  203.                     '?introspect=', urlencode(htmlspecialchars($_GET['introspect'])),
  204.                     '">Return to ', htmlspecialchars($_GET['introspect']), '</a><br />';
  205.             }
  206.             echo $source;
  207.             return false;
  208.         } else {
  209.             header("HTTP/1.0 404 Not Found");
  210.             return false;
  211.         }
  212.        
  213.     }
  214.  
  215.     public static function introspect($archive, $dir)
  216.     {
  217.         // security, idea borrowed from PHK
  218.         if (!file_exists($archive . '.introspect')) {
  219.             header("HTTP/1.0 404 Not Found");
  220.             return false;
  221.         }
  222.         if (!$dir) {
  223.             $dir = '/';
  224.         }
  225.         $dir = self::processFile($dir);
  226.         if ($dir[0] != '/') {
  227.             $dir = '/' . $dir;
  228.         }
  229.         try {
  230.             $self = htmlspecialchars($_SERVER['PHP_SELF']);
  231.             $iterate = new DirectoryIterator('phar://go-pear.phar' . $dir);
  232.             echo '<html><head><title>Introspect ', htmlspecialchars($dir),
  233.                 '</title></head><body><h1>Introspect ', htmlspecialchars($dir),
  234.                 '</h1><ul>';
  235.             if ($dir != '/') {
  236.                 echo '<li><a href="', $self, '?introspect=',
  237.                     htmlspecialchars(dirname($dir)), '">..</a></li>';
  238.             }
  239.             foreach ($iterate as $entry) {
  240.                 if ($entry->isDot()) continue;
  241.                 $name = self::processFile($entry->getPathname());
  242.                 $name = str_replace('phar://go-pear.phar/', '', $name);
  243.                 if ($entry->isDir()) {
  244.                     echo '<li><a href="', $self, '?introspect=',
  245.                         urlencode(htmlspecialchars($name)),
  246.                         '">',
  247.                         htmlspecialchars($entry->getFilename()), '/</a> [directory]</li>';
  248.                 } else {
  249.                     echo '<li><a href="', $self, '?introspect=',
  250.                         urlencode(htmlspecialchars($dir)), '&viewsource=',
  251.                         urlencode(htmlspecialchars($name)),
  252.                         '">',
  253.                         htmlspecialchars($entry->getFilename()), '</a></li>';
  254.                 }
  255.             }
  256.             return false;
  257.         } catch (Exception $e) {
  258.             echo '<html><head><title>Directory not found: ',
  259.                 htmlspecialchars($dir), '</title></head>',
  260.                 '<body><h1>Directory not found: ', htmlspecialchars($dir), '</h1>',
  261.                 '<p>Try <a href="', htmlspecialchars($_SERVER['PHP_SELF']), '?introspect=/">',
  262.                 'This link</a></p></body></html>';
  263.             return false;
  264.         }
  265.     }
  266.  
  267.     public static function webFrontController($initfile)
  268.     {
  269.         if (isset($_SERVER) && isset($_SERVER['REQUEST_URI'])) {
  270.             $uri = parse_url($_SERVER['REQUEST_URI']);
  271.             $archive = realpath($_SERVER['SCRIPT_FILENAME']);
  272.             $subpath = str_replace('/' . basename($archive), '', $uri['path']);
  273.             if (!$subpath || $subpath == '/') {
  274.                 if (isset($_GET['viewsource'])) {
  275.                     return self::viewSource($archive, $_GET['viewsource']);
  276.                 }
  277.                 if (isset($_GET['introspect'])) {
  278.                     return self::introspect($archive, $_GET['introspect']);
  279.                 }
  280.                 $subpath = '/' . $initfile;
  281.             }
  282.             if (!self::_fileExists($archive, substr($subpath, 1))) {
  283.                 header("HTTP/1.0 404 Not Found");
  284.                 return false;
  285.             }
  286.             foreach (self::$deny as $pattern) {
  287.                 if (preg_match($pattern, $subpath)) {
  288.                     header("HTTP/1.0 404 Not Found");
  289.                     return false;
  290.                 }
  291.             }
  292.             $inf = pathinfo(basename($subpath));
  293.             if (!isset($inf['extension'])) {
  294.                 header('Content-Type: text/plain');
  295.                 header('Content-Length: ' .
  296.                     self::_filesize($archive, substr($subpath, 1)));
  297.                 readfile('phar://go-pear.phar' . $subpath);
  298.                 return false;
  299.             }
  300.             if (isset(self::$defaultphp[$inf['extension']])) {
  301.                 include 'phar://go-pear.phar' . $subpath;
  302.                 return false;
  303.             }
  304.             if (isset(self::$defaultmimes[$inf['extension']])) {
  305.                 header('Content-Type: ' . self::$defaultmimes[$inf['extension']]);
  306.                 header('Content-Length: ' .
  307.                     self::_filesize($archive, substr($subpath, 1)));
  308.                 readfile('phar://go-pear.phar' . $subpath);
  309.                 return false;
  310.             }
  311.             if (isset(self::$defaultphps[$inf['extension']])) {
  312.                 header('Content-Type: text/html');
  313.                 $c = highlight_file('phar://go-pear.phar' . $subpath, true);
  314.                 header('Content-Length: ' . strlen($c));
  315.                 echo $c;
  316.                 return false;
  317.             }
  318.             header('Content-Type: text/plain');
  319.             header('Content-Length: ' .
  320.                     self::_filesize($archive, substr($subpath, 1)));
  321.             readfile('phar://go-pear.phar' . $subpath);
  322.         }
  323.     }
  324.  
  325.     /**
  326.      * Detect end of stub
  327.      *
  328.      * @param string $buffer stub past '__HALT_'.'COMPILER();'
  329.      * @return end of stub, prior to length of manifest.
  330.      */
  331.     private static final function _endOfStubLength($buffer)
  332.     {
  333.         $pos = 0;
  334.         if (!strlen($buffer)) {
  335.             return $pos;
  336.         }
  337.         if (($buffer[0] == ' ' || $buffer[0] == "\n") && @substr($buffer, 1, 2) == '')
  338.         {
  339.             $pos += 3;
  340.             if ($buffer[$pos] == "\r" && $buffer[$pos+1] == "\n") {
  341.                 $pos += 2;
  342.             }
  343.             else if ($buffer[$pos] == "\n") {
  344.                 $pos += 1;
  345.             }
  346.         }
  347.         return $pos;
  348.     }
  349.  
  350.     /**
  351.      * Allows loading an external Phar archive without include()ing it
  352.      *
  353.      * @param string $file  phar package to load
  354.      * @param string $alias alias to use
  355.      * @throws Exception
  356.      */
  357.     public static final function loadPhar($file, $alias = NULL)
  358.     {
  359.         $file = realpath($file);
  360.         if ($file) {
  361.             $fp = fopen($file, 'rb');
  362.             $buffer = '';
  363.             while (!feof($fp)) {
  364.                 $buffer .= fread($fp, 8192);
  365.                 // don't break phars
  366.                 if ($pos = strpos($buffer, '__HALT_COMPI' . 'LER();')) {
  367.                     $buffer .= fread($fp, 5);
  368.                     fclose($fp);
  369.                     $pos += 18;
  370.                     $pos += self::_endOfStubLength(substr($buffer, $pos));
  371.                     return self::_mapPhar($file, $pos, $alias);
  372.                 }
  373.             }
  374.             fclose($fp);
  375.         }
  376.     }
  377.  
  378.     /**
  379.      * Map a full real file path to an alias used to refer to the .phar
  380.      *
  381.      * This function can only be called from the initialization of the .phar itself.
  382.      * Any attempt to call from outside the .phar or to re-alias the .phar will fail
  383.      * as a security measure.
  384.      * @param string $alias
  385.      * @param int $dataoffset the value of 42313                  
  386.      */
  387.     public static final function mapPhar($alias = NULL, $dataoffset = NULL)
  388.     {
  389.         try {
  390.             $trace = debug_backtrace();
  391.             $file = $trace[0]['file'];
  392.             // this ensures that this is safe
  393.             if (!in_array($file, get_included_files())) {
  394.                 die('SECURITY ERROR: PHP_Archive::mapPhar can only be called from within ' .
  395.                     'the phar that initiates it');
  396.             }
  397.             $file = realpath($file);
  398.             if (!isset($dataoffset)) {
  399.                 $dataoffset = constant('__COMPILER_HALT_OFFSET'.'__');
  400.                 $fp = fopen($file, 'rb');
  401.                 fseek($fp, $dataoffset, SEEK_SET);
  402.                 $dataoffset = $dataoffset + self::_endOfStubLength(fread($fp, 5));
  403.                 fclose($fp);
  404.             }
  405.  
  406.             self::_mapPhar($file, $dataoffset);
  407.         } catch (Exception $e) {
  408.             die($e->getMessage());
  409.         }
  410.     }
  411.  
  412.     /**
  413.      * Sub-function, allows recovery from errors
  414.      *
  415.      * @param unknown_type $file
  416.      * @param unknown_type $dataoffset
  417.      */
  418.     private static function _mapPhar($file, $dataoffset, $alias = NULL)
  419.     {
  420.         $file = realpath($file);
  421.         if (isset(self::$_manifest[$file])) {
  422.             return;
  423.         }
  424.         if (!is_array(self::$_pharMapping)) {
  425.             self::$_pharMapping = array();
  426.         }
  427.         $fp = fopen($file, 'rb');
  428.         // seek to __HALT_COMPILER_OFFSET__
  429.         fseek($fp, $dataoffset);
  430.         $manifest_length = unpack('Vlen', fread($fp, 4));
  431.         $manifest = '';
  432.         $last = '1';
  433.         while (strlen($last) && strlen($manifest) < $manifest_length['len']) {
  434.             $read = 8192;
  435.             if ($manifest_length['len'] - strlen($manifest) < 8192) {
  436.                 $read = $manifest_length['len'] - strlen($manifest);
  437.             }
  438.             $last = fread($fp, $read);
  439.             $manifest .= $last;
  440.         }
  441.         if (strlen($manifest) < $manifest_length['len']) {
  442.             throw new Exception('ERROR: manifest length read was "' .
  443.                 strlen($manifest) .'" should be "' .
  444.                 $manifest_length['len'] . '"');
  445.         }
  446.         $info = self::_unserializeManifest($manifest);
  447.         if ($info['alias']) {
  448.             $alias = $info['alias'];
  449.             $explicit = true;
  450.         } else {
  451.             if (!isset($alias)) {
  452.                 $alias = $file;
  453.             }
  454.             $explicit = false;
  455.         }
  456.         self::$_manifest[$file] = $info['manifest'];
  457.         $compressed = $info['compressed'];
  458.         self::$_fileStart[$file] = ftell($fp);
  459.         fclose($fp);
  460.         if ($compressed & 0x00001000) {
  461.             if (!function_exists('gzinflate')) {
  462.                 throw new Exception('Error: zlib extension is not enabled - gzinflate() function needed' .
  463.                     ' for compressed .phars');
  464.             }
  465.         }
  466.         if ($compressed & 0x00002000) {
  467.             if (!function_exists('bzdecompress')) {
  468.                 throw new Exception('Error: bzip2 extension is not enabled - bzdecompress() function needed' .
  469.                     ' for compressed .phars');
  470.             }
  471.         }
  472.         if (isset(self::$_pharMapping[$alias])) {
  473.             throw new Exception('ERROR: PHP_Archive::mapPhar has already been called for alias "' .
  474.                 $alias . '" cannot re-alias to "' . $file . '"');
  475.         }
  476.         self::$_pharMapping[$alias] = array($file, $compressed, $dataoffset, $explicit,
  477.             $info['metadata']);
  478.         self::$_pharFiles[$file] = $alias;
  479.     }
  480.  
  481.     /**
  482.      * extract the manifest into an internal array
  483.      *
  484.      * @param string $manifest
  485.      * @return false|array
  486.      */
  487.     private static function _unserializeManifest($manifest)
  488.     {
  489.         // retrieve the number of files in the manifest
  490.         $info = unpack('V', substr($manifest, 0, 4));
  491.         $apiver = substr($manifest, 4, 2);
  492.         $apiver = bin2hex($apiver);
  493.         $apiver_dots = hexdec($apiver[0]) . '.' . hexdec($apiver[1]) . '.' . hexdec($apiver[2]);
  494.         $majorcompat = hexdec($apiver[0]);
  495.         $calcapi = explode('.', self::APIVersion());
  496.         if ($calcapi[0] != $majorcompat) {
  497.             throw new Exception('Phar is incompatible API version ' . $apiver_dots . ', but ' .
  498.                 'PHP_Archive is API version '.self::APIVersion());
  499.         }
  500.         if ($calcapi[0] === '0') {
  501.             if (self::APIVersion() != $apiver_dots) {
  502.                 throw new Exception('Phar is API version ' . $apiver_dots .
  503.                     ', but PHP_Archive is API version '.self::APIVersion(), E_USER_ERROR);
  504.             }
  505.         }
  506.         $flags = unpack('V', substr($manifest, 6, 4));
  507.         $ret = array('compressed' => $flags & 0x00003000);
  508.         // signature is not verified by default in PHP_Archive, phar is better
  509.         $ret['hassignature'] = $flags & 0x00010000;
  510.         $aliaslen = unpack('V', substr($manifest, 10, 4));
  511.         if ($aliaslen) {
  512.             $ret['alias'] = substr($manifest, 14, $aliaslen[1]);
  513.         } else {
  514.             $ret['alias'] = false;
  515.         }
  516.         $manifest = substr($manifest, 14 + $aliaslen[1]);
  517.         $metadatalen = unpack('V', substr($manifest, 0, 4));
  518.         if ($metadatalen[1]) {
  519.             $ret['metadata'] = unserialize(substr($manifest, 4, $metadatalen[1]));
  520.             $manifest = substr($manifest, 4 + $metadatalen[1]);
  521.         } else {
  522.             $ret['metadata'] = null;
  523.             $manifest = substr($manifest, 4);
  524.         }
  525.         $offset = 0;
  526.         $start = 0;
  527.         for ($i = 0; $i < $info[1]; $i++) {
  528.             // length of the file name
  529.             $len = unpack('V', substr($manifest, $start, 4));
  530.             $start += 4;
  531.             // file name
  532.             $savepath = substr($manifest, $start, $len[1]);
  533.             $start += $len[1];
  534.             // retrieve manifest data:
  535.             // 0 = uncompressed file size
  536.             // 1 = timestamp of when file was added to phar
  537.             // 2 = compressed filesize
  538.             // 3 = crc32
  539.             // 4 = flags
  540.             // 5 = metadata length
  541.             $ret['manifest'][$savepath] = array_values(unpack('Va/Vb/Vc/Vd/Ve/Vf', substr($manifest, $start, 24)));
  542.             $ret['manifest'][$savepath][3] = sprintf('%u', $ret['manifest'][$savepath][3]
  543.                 & 0xffffffff);
  544.             if ($ret['manifest'][$savepath][5]) {
  545.                 $ret['manifest'][$savepath][6] = unserialize(substr($manifest, $start + 24,
  546.                     $ret['manifest'][$savepath][5]));
  547.             } else {
  548.                 $ret['manifest'][$savepath][6] = null;
  549.             }
  550.             $ret['manifest'][$savepath][7] = $offset;
  551.             $offset += $ret['manifest'][$savepath][2];
  552.             $start += 24 + $ret['manifest'][$savepath][5];
  553.         }
  554.         return $ret;
  555.     }
  556.  
  557.     /**
  558.      * @param string
  559.      */
  560.     private static function processFile($path)
  561.     {
  562.         if ($path == '.') {
  563.             return '';
  564.         }
  565.         $std = str_replace("\\", "/", $path);
  566.         while ($std != ($std = ereg_replace("[^\/:?]+/\.\./", "", $std))) ;
  567.         $std = str_replace("/./", "", $std);
  568.         if (strlen($std) > 1 && $std[0] == '/') {
  569.             $std = substr($std, 1);
  570.         }
  571.         if (strncmp($std, "./", 2) == 0) {
  572.             return substr($std, 2);
  573.         } else {
  574.             return $std;
  575.         }
  576.     }
  577.  
  578.     /**
  579.      * Seek in the master archive to a matching file or directory
  580.      * @param string
  581.      */
  582.     protected function selectFile($path, $allowdirs = true)
  583.     {
  584.         $std = self::processFile($path);
  585.         if (isset(self::$_manifest[$this->_archiveName][$path])) {
  586.             $this->_setCurrentFile($path);
  587.             return true;
  588.         }
  589.         if (!$allowdirs) {
  590.             return 'Error: "' . $path . '" is not a file in phar "' . $this->_basename . '"';
  591.         }
  592.         foreach (self::$_manifest[$this->_archiveName] as $file => $info) {
  593.             if (empty($std) ||
  594.                   //$std is a directory
  595.                   strncmp($std.'/', $path, strlen($std)+1) == 0) {
  596.                 $this->currentFilename = $this->internalFileLength = $this->currentStat = null;
  597.                 return true;
  598.             }
  599.         }
  600.         return 'Error: "' . $path . '" not found in phar "' . $this->_basename . '"';
  601.     }
  602.  
  603.     private function _setCurrentFile($path)
  604.     {
  605.         $this->currentStat = array(
  606.             2 => 0100444, // file mode, readable by all, writeable by none
  607.             4 => 0, // uid
  608.             5 => 0, // gid
  609.             7 => self::$_manifest[$this->_archiveName][$path][0], // size
  610.             9 => self::$_manifest[$this->_archiveName][$path][1], // creation time
  611.             );
  612.         $this->currentFilename = $path;
  613.         $this->internalFileLength = self::$_manifest[$this->_archiveName][$path][2];
  614.         // seek to offset of file header within the .phar
  615.         if (is_resource(@$this->fp)) {
  616.             fseek($this->fp, self::$_fileStart[$this->_archiveName] + self::$_manifest[$this->_archiveName][$path][7]);
  617.         }
  618.     }
  619.  
  620.     private static function _fileExists($archive, $path)
  621.     {
  622.         return isset(self::$_manifest[$archive]) &&
  623.             isset(self::$_manifest[$archive][$path]);
  624.     }
  625.  
  626.     private static function _filesize($archive, $path)
  627.     {
  628.         return self::$_manifest[$archive][$path][0];
  629.     }
  630.  
  631.     /**
  632.      * Seek to a file within the master archive, and extract its contents
  633.      * @param string
  634.      * @return array|string an array containing an error message string is returned
  635.      *                      upon error, otherwise the file contents are returned
  636.      */
  637.     public function extractFile($path)
  638.     {
  639.         $this->fp = @fopen($this->_archiveName, "rb");
  640.         if (!$this->fp) {
  641.             return array('Error: cannot open phar "' . $this->_archiveName . '"');
  642.         }
  643.         if (($e = $this->selectFile($path, false)) === true) {
  644.             $data = '';
  645.             $count = $this->internalFileLength;
  646.             while ($count) {
  647.                 if ($count < 8192) {
  648.                     $data .= @fread($this->fp, $count);
  649.                     $count = 0;
  650.                 } else {
  651.                     $count -= 8192;
  652.                     $data .= @fread($this->fp, 8192);
  653.                 }
  654.             }
  655.             @fclose($this->fp);
  656.             if (self::$_manifest[$this->_archiveName][$path][4] & self::GZ) {
  657.                 $data = gzinflate($data);
  658.             } elseif (self::$_manifest[$this->_archiveName][$path][4] & self::BZ2) {
  659.                 $data = bzdecompress($data);
  660.             }
  661.             if (!isset(self::$_manifest[$this->_archiveName][$path]['ok'])) {
  662.                 if (strlen($data) != $this->currentStat[7]) {
  663.                     return array("Not valid internal .phar file (size error {$size} != " .
  664.                         $this->currentStat[7] . ")");
  665.                 }
  666.                 if (self::$_manifest[$this->_archiveName][$path][3] != sprintf("%u", crc32($data) & 0xffffffff)) {
  667.                     return array("Not valid internal .phar file (checksum error)");
  668.                 }
  669.                 self::$_manifest[$this->_archiveName][$path]['ok'] = true;
  670.             }
  671.             return $data;
  672.         } else {
  673.             @fclose($this->fp);
  674.             return array($e);
  675.         }
  676.     }
  677.  
  678.     /**
  679.      * Parse urls like phar:///fullpath/to/my.phar/file.txt
  680.      *
  681.      * @param string $file
  682.      * @return false|array
  683.      */
  684.     static protected function parseUrl($file)
  685.     {
  686.         if (substr($file, 0, 7) != 'phar://') {
  687.             return false;
  688.         }
  689.         $file = substr($file, 7);
  690.    
  691.         $ret = array('scheme' => 'phar');
  692.         $pos_p = strpos($file, '.phar.php');
  693.         $pos_z = strpos($file, '.phar.gz');
  694.         $pos_b = strpos($file, '.phar.bz2');
  695.         if ($pos_p) {
  696.             if ($pos_z) {
  697.                 return false;
  698.             }
  699.             $ret['host'] = substr($file, 0, $pos_p + strlen('.phar.php'));
  700.             $ret['path'] = substr($file, strlen($ret['host']));
  701.         } elseif ($pos_z) {
  702.             $ret['host'] = substr($file, 0, $pos_z + strlen('.phar.gz'));
  703.             $ret['path'] = substr($file, strlen($ret['host']));
  704.         } elseif ($pos_b) {
  705.             $ret['host'] = substr($file, 0, $pos_z + strlen('.phar.bz2'));
  706.             $ret['path'] = substr($file, strlen($ret['host']));
  707.         } elseif (($pos_p = strpos($file, ".phar")) !== false) {
  708.             $ret['host'] = substr($file, 0, $pos_p + strlen('.phar'));
  709.             $ret['path'] = substr($file, strlen($ret['host']));
  710.         } else {
  711.             return false;
  712.         }
  713.         if (!$ret['path']) {
  714.             $ret['path'] = '/';
  715.         }
  716.         return $ret;
  717.     }
  718.    
  719.     /**
  720.      * Locate the .phar archive in the include_path and detect the file to open within
  721.      * the archive.
  722.      *
  723.      * Possible parameters are phar://pharname.phar/filename_within_phar.ext
  724.      * @param string a file within the archive
  725.      * @return string the filename within the .phar to retrieve
  726.      */
  727.     public function initializeStream($file)
  728.     {
  729.         $file = self::processFile($file);
  730.         $info = @parse_url($file);
  731.         if (!$info) {
  732.             $info = self::parseUrl($file);
  733.         }
  734.         if (!$info) {
  735.             return false;
  736.         }
  737.         if (!isset($info['host'])) {
  738.             // malformed internal file
  739.             return false;
  740.         }
  741.         if (!isset(self::$_pharFiles[$info['host']]) &&
  742.               !isset(self::$_pharMapping[$info['host']])) {
  743.             try {
  744.                 self::loadPhar($info['host']);
  745.                 // use alias from here out
  746.                 $info['host'] = self::$_pharFiles[$info['host']];
  747.             } catch (Exception $e) {
  748.                 return false;
  749.             }
  750.         }
  751.         if (!isset($info['path'])) {
  752.             return false;
  753.         } elseif (strlen($info['path']) > 1) {
  754.             $info['path'] = substr($info['path'], 1);
  755.         }
  756.         if (isset(self::$_pharMapping[$info['host']])) {
  757.             $this->_basename = $info['host'];
  758.             $this->_archiveName = self::$_pharMapping[$info['host']][0];
  759.             $this->_compressed = self::$_pharMapping[$info['host']][1];
  760.         } elseif (isset(self::$_pharFiles[$info['host']])) {
  761.             $this->_archiveName = $info['host'];
  762.             $this->_basename = self::$_pharFiles[$info['host']];
  763.             $this->_compressed = self::$_pharMapping[$this->_basename][1];
  764.         }
  765.         $file = $info['path'];
  766.         return $file;
  767.     }
  768.  
  769.     /**
  770.      * Open the requested file - PHP streams API
  771.      *
  772.      * @param string $file String provided by the Stream wrapper
  773.      * @access private
  774.      */
  775.     public function stream_open($file)
  776.     {
  777.         return $this->_streamOpen($file);
  778.     }
  779.  
  780.     /**
  781.      * @param string filename to opne, or directory name
  782.      * @param bool if true, a directory will be matched, otherwise only files
  783.      *             will be matched
  784.      * @uses trigger_error()
  785.      * @return bool success of opening
  786.      * @access private
  787.      */
  788.     private function _streamOpen($file, $searchForDir = false)
  789.     {
  790.         $path = $this->initializeStream($file);
  791.         if (!$path) {
  792.             trigger_error('Error: Unknown phar in "' . $file . '"', E_USER_ERROR);
  793.         }
  794.         if (is_array($this->file = $this->extractFile($path))) {
  795.             trigger_error($this->file[0], E_USER_ERROR);
  796.             return false;
  797.         }
  798.         if ($path != $this->currentFilename) {
  799.             if (!$searchForDir) {
  800.                 trigger_error("Cannot open '$file', is a directory", E_USER_ERROR);
  801.                 return false;
  802.             } else {
  803.                 $this->file = '';
  804.                 return true;
  805.             }
  806.         }
  807.  
  808.         if (!is_null($this->file) && $this->file !== false) {
  809.             return true;
  810.         } else {
  811.             return false;
  812.         }
  813.     }
  814.    
  815.     /**
  816.      * Read the data - PHP streams API
  817.      *
  818.      * @param int
  819.      * @access private
  820.      */
  821.     public function stream_read($count)
  822.     {
  823.         $ret = substr($this->file, $this->position, $count);
  824.         $this->position += strlen($ret);
  825.         return $ret;
  826.     }
  827.    
  828.     /**
  829.      * Whether we've hit the end of the file - PHP streams API
  830.      * @access private
  831.      */
  832.     function stream_eof()
  833.     {
  834.         return $this->position >= $this->currentStat[7];
  835.     }
  836.    
  837.     /**
  838.      * For seeking the stream - PHP streams API
  839.      * @param int
  840.      * @param SEEK_SET|SEEK_CUR|SEEK_END
  841.      * @access private
  842.      */
  843.     public function stream_seek($pos, $whence)
  844.     {
  845.         switch ($whence) {
  846.             case SEEK_SET:
  847.                 if ($pos < 0) {
  848.                     return false;
  849.                 }
  850.                 $this->position = $pos;
  851.                 break;
  852.             case SEEK_CUR:
  853.                 if ($pos + $this->currentStat[7] < 0) {
  854.                     return false;
  855.                 }
  856.                 $this->position += $pos;
  857.                 break;
  858.             case SEEK_END:
  859.                 if ($pos + $this->currentStat[7] < 0) {
  860.                     return false;
  861.                 }
  862.                 $this->position = $pos + $this->currentStat[7];
  863.                 break;
  864.             default:
  865.                 return false;
  866.         }
  867.         return true;
  868.     }
  869.    
  870.     /**
  871.      * The current position in the stream - PHP streams API
  872.      * @access private
  873.      */
  874.     public function stream_tell()
  875.     {
  876.         return $this->position;
  877.     }
  878.  
  879.     /**
  880.      * The result of an fstat call, returns mod time from creation, and file size -
  881.      * PHP streams API
  882.      * @uses _stream_stat()
  883.      * @access private
  884.      */
  885.     public function stream_stat()
  886.     {
  887.         return $this->_stream_stat();
  888.     }
  889.  
  890.     /**
  891.      * Retrieve statistics on a file or directory within the .phar
  892.      * @param string file/directory to stat
  893.      * @access private
  894.      */
  895.     public function _stream_stat($file = null)
  896.     {
  897.         $std = $file ? self::processFile($file) : $this->currentFilename;
  898.         if ($file) {
  899.             if (isset(self::$_manifest[$this->_archiveName][$file])) {
  900.                 $this->_setCurrentFile($file);
  901.                 $isdir = false;
  902.             } else {
  903.                 do {
  904.                     $isdir = false;
  905.                     if ($file == '/') {
  906.                         break;
  907.                     }
  908.                     foreach (self::$_manifest[$this->_archiveName] as $path => $info) {
  909.                         if (strpos($path, $file) === 0) {
  910.                             if (strlen($path) > strlen($file) &&
  911.                                   $path[strlen($file)] == '/') {
  912.                                 break 2;
  913.                             }
  914.                         }
  915.                     }
  916.                     // no files exist and no directories match this string
  917.                     return false;
  918.                 } while (false);
  919.                 $isdir = true;
  920.             }
  921.         } else {
  922.             $isdir = false; // open streams must be files
  923.         }
  924.         $mode = $isdir ? 0040444 : 0100444;
  925.         // 040000 = dir, 010000 = file
  926.         // everything is readable, nothing is writeable
  927.         return array(
  928.            0, 0, $mode, 0, 0, 0, 0, 0, 0, 0, 0, 0, // non-associative indices
  929.            'dev' => 0, 'ino' => 0,
  930.            'mode' => $mode,
  931.            'nlink' => 0, 'uid' => 0, 'gid' => 0, 'rdev' => 0, 'blksize' => 0, 'blocks' => 0,
  932.            'size' => $this->currentStat[7],
  933.            'atime' => $this->currentStat[9],
  934.            'mtime' => $this->currentStat[9],
  935.            'ctime' => $this->currentStat[9],
  936.            );
  937.     }
  938.  
  939.     /**
  940.      * Stat a closed file or directory - PHP streams API
  941.      * @param string
  942.      * @param int
  943.      * @access private
  944.      */
  945.     public function url_stat($url, $flags)
  946.     {
  947.         $path = $this->initializeStream($url);
  948.         return $this->_stream_stat($path);
  949.     }
  950.  
  951.     /**
  952.      * Open a directory in the .phar for reading - PHP streams API
  953.      * @param string directory name
  954.      * @access private
  955.      */
  956.     public function dir_opendir($path)
  957.     {
  958.         $info = @parse_url($path);
  959.         if (!$info) {
  960.             $info = self::parseUrl($path);
  961.             if (!$info) {
  962.                 trigger_error('Error: "' . $path . '" is a file, and cannot be opened with opendir',
  963.                     E_USER_ERROR);
  964.                 return false;
  965.             }
  966.         }
  967.         $path = !empty($info['path']) ?
  968.             $info['host'] . $info['path'] : $info['host'] . '/';
  969.         $path = $this->initializeStream('phar://' . $path);
  970.         if (isset(self::$_manifest[$this->_archiveName][$path])) {
  971.             trigger_error('Error: "' . $path . '" is a file, and cannot be opened with opendir',
  972.                 E_USER_ERROR);
  973.             return false;
  974.         }
  975.         if ($path == false) {
  976.             trigger_error('Error: Unknown phar in "' . $file . '"', E_USER_ERROR);
  977.             return false;
  978.         }
  979.         $this->fp = @fopen($this->_archiveName, "rb");
  980.         if (!$this->fp) {
  981.             trigger_error('Error: cannot open phar "' . $this->_archiveName . '"');
  982.             return false;
  983.         }
  984.         $this->_dirFiles = array();
  985.         foreach (self::$_manifest[$this->_archiveName] as $file => $info) {
  986.             if ($path == '/') {
  987.                 if (strpos($file, '/')) {
  988.                     $a = explode('/', $file);
  989.                     $this->_dirFiles[array_shift($a)] = true;
  990.                 } else {
  991.                     $this->_dirFiles[$file] = true;
  992.                 }
  993.             } elseif (strpos($file, $path) === 0) {
  994.                 $fname = substr($file, strlen($path) + 1);
  995.                 if (strpos($fname, '/')) {
  996.                     // this is a directory
  997.                     $a = explode('/', $fname);
  998.                     $this->_dirFiles[array_shift($a)] = true;
  999.                 } elseif ($file[strlen($path)] == '/') {
  1000.                     // this is a file
  1001.                     $this->_dirFiles[$fname] = true;
  1002.                 }
  1003.             }
  1004.         }
  1005.         @fclose($this->fp);
  1006.         if (!count($this->_dirFiles)) {
  1007.             return false;
  1008.         }
  1009.         @uksort($this->_dirFiles, 'strnatcmp');
  1010.         return true;
  1011.     }
  1012.  
  1013.     /**
  1014.      * Read the next directory entry - PHP streams API
  1015.      * @access private
  1016.      */
  1017.     public function dir_readdir()
  1018.     {
  1019.         $ret = key($this->_dirFiles);
  1020.         @next($this->_dirFiles);
  1021.         if (!$ret) {
  1022.             return false;
  1023.         }
  1024.         return $ret;
  1025.     }
  1026.  
  1027.     /**
  1028.      * Close a directory handle opened with opendir() - PHP streams API
  1029.      * @access private
  1030.      */
  1031.     public function dir_closedir()
  1032.     {
  1033.         $this->_dirFiles = array();
  1034.         return true;
  1035.     }
  1036.  
  1037.     /**
  1038.      * Rewind to the first directory entry - PHP streams API
  1039.      * @access private
  1040.      */
  1041.     public function dir_rewinddir()
  1042.     {
  1043.         @reset($this->_dirFiles);
  1044.         return true;
  1045.     }
  1046.  
  1047.     /**
  1048.      * API version of this class
  1049.      * @return string
  1050.      */
  1051.     public static final function APIVersion()
  1052.     {
  1053.         return '1.0.0';
  1054.     }
  1055.  
  1056.     /**
  1057.      * Retrieve Phar-specific metadata for a Phar archive
  1058.      *
  1059.      * @param string $phar full path to Phar archive, or alias
  1060.      * @return null|mixed The value that was serialized for the Phar
  1061.      *                    archive's metadata
  1062.      * @throws Exception
  1063.      */
  1064.     public static function getPharMetadata($phar)
  1065.     {
  1066.         if (isset(self::$_pharFiles[$phar])) {
  1067.             $phar = self::$_pharFiles[$phar];
  1068.         }
  1069.         if (!isset(self::$_pharMapping[$phar])) {
  1070.             throw new Exception('Unknown Phar archive: "' . $phar . '"');
  1071.         }
  1072.         return self::$_pharMapping[$phar][4];
  1073.     }
  1074.  
  1075.     /**
  1076.      * Retrieve File-specific metadata for a Phar archive file
  1077.      *
  1078.      * @param string $phar full path to Phar archive, or alias
  1079.      * @param string $file relative path to file within Phar archive
  1080.      * @return null|mixed The value that was serialized for the Phar
  1081.      *                    archive's metadata
  1082.      * @throws Exception
  1083.      */
  1084.     public static function getFileMetadata($phar, $file)
  1085.     {
  1086.         if (!isset(self::$_pharFiles[$phar])) {
  1087.             if (!isset(self::$_pharMapping[$phar])) {
  1088.                 throw new Exception('Unknown Phar archive: "' . $phar . '"');
  1089.             }
  1090.             $phar = self::$_pharMapping[$phar][0];
  1091.         }
  1092.         if (!isset(self::$_manifest[$phar])) {
  1093.             throw new Exception('Unknown Phar: "' . $phar . '"');
  1094.         }
  1095.         $file = self::processFile($file);
  1096.         if (!isset(self::$_manifest[$phar][$file])) {
  1097.             throw new Exception('Unknown file "' . $file . '" within Phar "'. $phar . '"');
  1098.         }
  1099.         return self::$_manifest[$phar][$file][6];
  1100.     }
  1101.  
  1102.     /**
  1103.      * @return list of supported signature algorithmns.
  1104.      */
  1105.     public static function getsupportedsignatures()
  1106.     {
  1107.         $ret = array('MD5', 'SHA-1');
  1108.         if (extension_loaded('hash')) {
  1109.             $ret[] = 'SHA-256';
  1110.             $ret[] = 'SHA-512';
  1111.         }
  1112.         return $ret;
  1113.     }
  1114. }}
  1115. if (!class_exists('Phar')) {
  1116.     PHP_Archive::mapPhar(null, 42313                   );
  1117. } else {
  1118.     try {
  1119.         Phar::mapPhar();
  1120.     } catch (Exception $e) {
  1121.         echo $e->getMessage();
  1122.     }
  1123. }
  1124. if (class_exists('PHP_Archive') && !in_array('phar', stream_get_wrappers())) {
  1125.     stream_wrapper_register('phar', 'PHP_Archive');
  1126. }
  1127.  
  1128. @ini_set('memory_limit', -1);
  1129. if (extension_loaded('phar')) {if (isset($_SERVER) && isset($_SERVER['REQUEST_URI'])) {
  1130.     $uri = parse_url($_SERVER['REQUEST_URI']);
  1131.     $archive = realpath($_SERVER['SCRIPT_FILENAME']);
  1132.     $subpath = str_replace('/' . basename($archive), '', $uri['path']);
  1133.     $mimetypes = array (
  1134.   'aif' => 'audio/x-aiff',
  1135.   'aiff' => 'audio/x-aiff',
  1136.   'arc' => 'application/octet-stream',
  1137.   'arj' => 'application/octet-stream',
  1138.   'art' => 'image/x-jg',
  1139.   'asf' => 'video/x-ms-asf',
  1140.   'asx' => 'video/x-ms-asf',
  1141.   'avi' => 'video/avi',
  1142.   'bin' => 'application/octet-stream',
  1143.   'bm' => 'image/bmp',
  1144.   'bmp' => 'image/bmp',
  1145.   'bz2' => 'application/x-bzip2',
  1146.   'css' => 'text/css',
  1147.   'doc' => 'application/msword',
  1148.   'dot' => 'application/msword',
  1149.   'dv' => 'video/x-dv',
  1150.   'dvi' => 'application/x-dvi',
  1151.   'eps' => 'application/postscript',
  1152.   'exe' => 'application/octet-stream',
  1153.   'gif' => 'image/gif',
  1154.   'gz' => 'application/x-gzip',
  1155.   'gzip' => 'application/x-gzip',
  1156.   'htm' => 'text/html',
  1157.   'html' => 'text/html',
  1158.   'ico' => 'image/x-icon',
  1159.   'jpe' => 'image/jpeg',
  1160.   'jpg' => 'image/jpeg',
  1161.   'jpeg' => 'image/jpeg',
  1162.   'js' => 'application/x-javascript',
  1163.   'log' => 'text/plain',
  1164.   'mid' => 'audio/x-midi',
  1165.   'mov' => 'video/quicktime',
  1166.   'mp2' => 'audio/mpeg',
  1167.   'mp3' => 'audio/mpeg3',
  1168.   'mpg' => 'audio/mpeg',
  1169.   'pdf' => 'aplication/pdf',
  1170.   'png' => 'image/png',
  1171.   'rtf' => 'application/rtf',
  1172.   'tif' => 'image/tiff',
  1173.   'tiff' => 'image/tiff',
  1174.   'txt' => 'text/plain',
  1175.   'xml' => 'text/xml',
  1176. );
  1177.     $phpfiles = array (
  1178.   'php' => true,
  1179. );
  1180.     $phpsfiles = array (
  1181.   'phps' => true,
  1182. );
  1183.     $deny = array (
  1184.   0 => '/.+\\.inc$/',
  1185. );
  1186.     $subpath = str_replace('/' . basename($archive), '', $uri['path']);
  1187.     if (!$subpath || $subpath == '/') {
  1188.         $subpath = '/PEAR.php';
  1189.     }
  1190.     if ($subpath[0] != '/') {
  1191.         $subpath = '/' . $subpath;
  1192.     }
  1193.     if (!@file_exists('phar://' . $archive . $subpath)) {
  1194.         header("HTTP/1.0 404 Not Found");
  1195.         exit;
  1196.     }
  1197.  
  1198.     foreach ($deny as $pattern) {
  1199.         if (preg_match($pattern, $subpath)) {
  1200.             header("HTTP/1.0 404 Not Found");
  1201.             exit;
  1202.         }
  1203.     }
  1204.     $inf = pathinfo(basename($subpath));
  1205.     if (!isset($inf['extension'])) {
  1206.         header('Content-Type: text/plain');
  1207.         header('Content-Length: ' . filesize('phar://' . $archive . $subpath));
  1208.         readfile('phar://' . $archive . $subpath);
  1209.         exit;
  1210.     }
  1211.     if (isset($phpfiles[$inf['extension']])) {
  1212.         include 'phar://' . $archive . '/' . $subpath;
  1213.         exit;
  1214.     }
  1215.     if (isset($mimetypes[$inf['extension']])) {
  1216.         header('Content-Type: ' . $mimetypes[$inf['extension']]);
  1217.         header('Content-Length: ' . filesize('phar://' . $archive . $subpath));
  1218.         readfile('phar://' . $archive . $subpath);
  1219.         exit;
  1220.     }
  1221.     if (isset($phpsfiles[$inf['extension']])) {
  1222.         header('Content-Type: text/html');
  1223.         $c = highlight_file('phar://' . $archive . $subpath, true);
  1224.         header('Content-Length: ' . strlen($c));
  1225.         echo $c;
  1226.         exit;
  1227.     }
  1228.     header('Content-Type: text/plain');
  1229.     header('Content-Length: ' . filesize('phar://' . $archive . '/' . $subpath));
  1230.     readfile('phar://' . $archive . '/' . $subpath);
  1231.     exit;
  1232. }} else {if (!empty($_SERVER['REQUEST_URI'])) {PHP_Archive::webFrontController('PEAR.php');exit;}}
  1233.  
  1234.  
  1235.  
  1236. require_once 'phar://go-pear.phar/index.php';
  1237. __HALT_COMPILER();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement