home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / Servidores / xampp-win32-1.6.7-installer.exe / php / PEAR / go-pear.phar < prev    next >
Encoding:
Text File  |  2008-05-02  |  3.5 MB  |  95,039 lines

Text Truncated. Only the first 1MB is shown below. Download the file for the complete contents.
  1. <?php
  2. error_reporting(E_ALL);
  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.51 2007/08/18 15:30:07 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 42314                   
  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, 42314                   );
  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();√
  1238. D go-pear.pharArchive/Tar.php±εw#╡G±ε`~┤EmConsole/Getopt.phpΦ(w#╡GΦ(∙i┤Km    index.phpïw#╡GïAÅ#m OS/Guess.phpQ+w#╡GQ+≡4úmPEAR.phpêw#╡Gê=¥UFmPEAR/ChannelFile.php9▀w#╡G9▀UÜP√mPEAR/ChannelFile/Parser.phpéw#╡Gé//-≈mPEAR/Command.phpr3w#╡Gr3<╗å¬mPEAR/Command/Common.php┘"w#╡G┘"»┤f&mPEAR/Command/Install.php'─w#╡G'─╥hCímPEAR/Command/Install.xmlCw#╡GC▄r√╙mPEAR/Common.phpîw#╡Gî¢d│╒mPEAR/Config.phplw#╡Gl$ßδmPEAR/Dependency2.phpH╤w#╡GH╤(r═εmPEAR/DependencyDB.phpïdw#╡Gïd=½*WmPEAR/Downloader.phpFw#╡GFπÄÉmPEAR/Downloader/Package.phpI)w#╡GI)Hα⌠mPEAR/ErrorStack.php┤äw#╡G┤ä═ïmPEAR/Frontend.php¿w#╡G¿{╢ªmPEAR/Frontend/CLI.php<nw#╡G<nΓÉ«m+PEAR/go-pear-tarballs/Archive_Tar-1.3.2.tarZw#╡GZñ│«m.PEAR/go-pear-tarballs/Console_Getopt-1.2.3.tarFw#╡GF╞Yx╒m$PEAR/go-pear-tarballs/PEAR-1.7.1.tarw#╡G^ ╜Bm0PEAR/go-pear-tarballs/Structures_Graph-1.0.2.tarXw#╡GX'▀(┴mPEAR/Installer.php╝w#╡G╝╕sjmPEAR/Installer/Role.php╞ w#╡G╞ ²ÖQêmPEAR/Installer/Role/Common.php⌡w#╡G⌡\3σ;mPEAR/Installer/Role/Data.php░w#╡G░K°I│mPEAR/Installer/Role/Data.xmlÆw#╡GÆfìszmPEAR/Installer/Role/Doc.php¡w#╡G¡J:qmPEAR/Installer/Role/Doc.xmlæw#╡Gæh&P*mPEAR/Installer/Role/Php.php¡w#╡G¡πªqpmPEAR/Installer/Role/Php.xml¡w#╡G¡z¥qìmPEAR/Installer/Role/Script.php╢w#╡G╢¡/ZûmPEAR/Installer/Role/Script.xml░w#╡G░@vº╨mPEAR/Installer/Role/Test.php░w#╡G░eemPEAR/Installer/Role/Test.xmlÆw#╡GÆB] mPEAR/PackageFile.phphAw#╡GhA K?░m!PEAR/PackageFile/Generator/v1.php╕╞w#╡G╕╞≈«.m!PEAR/PackageFile/Generator/v2.phpàφw#╡Gàφî∩«*mPEAR/PackageFile/Parser/v1.phpQBw#╡GQBÇ6!8mPEAR/PackageFile/Parser/v2.php∩
  1239. w#╡G∩
  1240. e ╢τmPEAR/PackageFile/v1.phpÖ╔w#╡GÖ╔]3mPEAR/PackageFile/v2.phpw#╡GïUäçm!PEAR/PackageFile/v2/Validator.phpτKw#╡GτKútQmPEAR/Registry.php !w#╡G !µ>7└mPEAR/Remote.phpæGw#╡GæG╖╓÷m
  1241. PEAR/REST.php╦:w#╡G╦:├cASmPEAR/REST/10.php≡|w#╡G≡|┴LbÄmPEAR/Start.php╢6w#╡G╢6\I═ämPEAR/Start/CLI.php╣Qw#╡G╣Qƒp|ÜmPEAR/Task/Common.phpVw#╡GV'ú√mPEAR/Task/Postinstallscript.phpΣ9w#╡GΣ9╪4[m"PEAR/Task/Postinstallscript/rw.phpWw#╡GW}╒╦mPEAR/Task/Replace.phpw#╡G∙    ½▐mPEAR/Task/Replace/rw.php├w#╡G├è╧Ö¢mPEAR/Task/Unixeol.phpX
  1242. w#╡GX
  1243. K╬mPEAR/Task/Unixeol/rw.php╙w#╡G╙+°óymPEAR/Task/Windowseol.phpT
  1244. w#╡GT
  1245. æ┴ÇmPEAR/Task/Windowseol/rw.phpΦw#╡GΦ5╚┼mPEAR/Validate.phppWw#╡GpWdε╧mPEAR/Validator/PECL.phpàw#╡GàáûmPEAR/XMLParser.phpjw#╡Gj▌_^╔mStructures/Graph.phpÑw#╡GÑ╥0è╒m,Structures/Graph/Manipulator/AcyclicTest.php╗w#╡G╗½Vä'm2Structures/Graph/Manipulator/TopologicalSorter.phpèw#╡Gè¬C╬╧mStructures/Graph/Node.php╠*w#╡G╠*«╟âm
  1246. System.phpNw#╡GNÿúc╧m<?php
  1247. /* vim: set ts=4 sw=4: */
  1248. // +----------------------------------------------------------------------+
  1249. // | PHP Version 4                                                        |
  1250. // +----------------------------------------------------------------------+
  1251. // | Copyright (c) 1997-2003 The PHP Group                                |
  1252. // +----------------------------------------------------------------------+
  1253. // | This source file is subject to version 3.0 of the PHP license,       |
  1254. // | that is bundled with this package in the file LICENSE, and is        |
  1255. // | available through the world-wide-web at the following url:           |
  1256. // | http://www.php.net/license/3_0.txt.                                  |
  1257. // | If you did not receive a copy of the PHP license and are unable to   |
  1258. // | obtain it through the world-wide-web, please send a note to          |
  1259. // | license@php.net so we can mail you a copy immediately.               |
  1260. // +----------------------------------------------------------------------+
  1261. // | Author: Vincent Blavet <vincent@phpconcept.net>                      |
  1262. // +----------------------------------------------------------------------+
  1263. //
  1264. // $Id: Tar.php,v 1.24 2007/01/06 04:03:32 cellog Exp $
  1265.  
  1266. require_once 'phar://go-pear.phar/' . 'PEAR.php';
  1267.  
  1268.  
  1269. define ('ARCHIVE_TAR_ATT_SEPARATOR', 90001);
  1270. define ('ARCHIVE_TAR_END_BLOCK', pack("a512", ''));
  1271.  
  1272. /**
  1273. * Creates a (compressed) Tar archive
  1274. *
  1275. * @author   Vincent Blavet <vincent@phpconcept.net>
  1276. * @version  $Revision: 1.24 $
  1277. * @package  Archive
  1278. */
  1279. class Archive_Tar extends PEAR
  1280. {
  1281.     /**
  1282.     * @var string Name of the Tar
  1283.     */
  1284.     var $_tarname='';
  1285.  
  1286.     /**
  1287.     * @var boolean if true, the Tar file will be gzipped
  1288.     */
  1289.     var $_compress=false;
  1290.  
  1291.     /**
  1292.     * @var string Type of compression : 'none', 'gz' or 'bz2'
  1293.     */
  1294.     var $_compress_type='none';
  1295.  
  1296.     /**
  1297.     * @var string Explode separator
  1298.     */
  1299.     var $_separator=' ';
  1300.  
  1301.     /**
  1302.     * @var file descriptor
  1303.     */
  1304.     var $_file=0;
  1305.  
  1306.     /**
  1307.     * @var string Local Tar name of a remote Tar (http:// or ftp://)
  1308.     */
  1309.     var $_temp_tarname='';
  1310.  
  1311.     // {{{ constructor
  1312.     /**
  1313.     * Archive_Tar Class constructor. This flavour of the constructor only
  1314.     * declare a new Archive_Tar object, identifying it by the name of the
  1315.     * tar file.
  1316.     * If the compress argument is set the tar will be read or created as a
  1317.     * gzip or bz2 compressed TAR file.
  1318.     *
  1319.     * @param    string  $p_tarname  The name of the tar archive to create
  1320.     * @param    string  $p_compress can be null, 'gz' or 'bz2'. This
  1321.     *                   parameter indicates if gzip or bz2 compression
  1322.     *                   is required.  For compatibility reason the
  1323.     *                   boolean value 'true' means 'gz'.
  1324.     * @access public
  1325.     */
  1326.     function Archive_Tar($p_tarname, $p_compress = null)
  1327.     {
  1328.         $this->PEAR();
  1329.         $this->_compress = false;
  1330.         $this->_compress_type = 'none';
  1331.         if (($p_compress === null) || ($p_compress == '')) {
  1332.             if (@file_exists($p_tarname)) {
  1333.                 if ($fp = @fopen($p_tarname, "rb")) {
  1334.                     // look for gzip magic cookie
  1335.                     $data = fread($fp, 2);
  1336.                     fclose($fp);
  1337.                     if ($data == "\37\213") {
  1338.                         $this->_compress = true;
  1339.                         $this->_compress_type = 'gz';
  1340.                     // No sure it's enought for a magic code ....
  1341.                     } elseif ($data == "BZ") {
  1342.                         $this->_compress = true;
  1343.                         $this->_compress_type = 'bz2';
  1344.                     }
  1345.                 }
  1346.             } else {
  1347.                 // probably a remote file or some file accessible
  1348.                 // through a stream interface
  1349.                 if (substr($p_tarname, -2) == 'gz') {
  1350.                     $this->_compress = true;
  1351.                     $this->_compress_type = 'gz';
  1352.                 } elseif ((substr($p_tarname, -3) == 'bz2') ||
  1353.                           (substr($p_tarname, -2) == 'bz')) {
  1354.                     $this->_compress = true;
  1355.                     $this->_compress_type = 'bz2';
  1356.                 }
  1357.             }
  1358.         } else {
  1359.             if (($p_compress === true) || ($p_compress == 'gz')) {
  1360.                 $this->_compress = true;
  1361.                 $this->_compress_type = 'gz';
  1362.             } else if ($p_compress == 'bz2') {
  1363.                 $this->_compress = true;
  1364.                 $this->_compress_type = 'bz2';
  1365.             } else {
  1366.                 die("Unsupported compression type '$p_compress'\n".
  1367.                     "Supported types are 'gz' and 'bz2'.\n");
  1368.                 return false;
  1369.             }
  1370.         }
  1371.         $this->_tarname = $p_tarname;
  1372.         if ($this->_compress) { // assert zlib or bz2 extension support
  1373.             if ($this->_compress_type == 'gz')
  1374.                 $extname = 'zlib';
  1375.             else if ($this->_compress_type == 'bz2')
  1376.                 $extname = 'bz2';
  1377.  
  1378.             if (!extension_loaded($extname)) {
  1379.                 PEAR::loadExtension($extname);
  1380.             }
  1381.             if (!extension_loaded($extname)) {
  1382.                 die("The extension '$extname' couldn't be found.\n".
  1383.                     "Please make sure your version of PHP was built ".
  1384.                     "with '$extname' support.\n");
  1385.                 return false;
  1386.             }
  1387.         }
  1388.     }
  1389.     // }}}
  1390.  
  1391.     // {{{ destructor
  1392.     function _Archive_Tar()
  1393.     {
  1394.         $this->_close();
  1395.         // ----- Look for a local copy to delete
  1396.         if ($this->_temp_tarname != '')
  1397.             @unlink($this->_temp_tarname);
  1398.         $this->_PEAR();
  1399.     }
  1400.     // }}}
  1401.  
  1402.     // {{{ create()
  1403.     /**
  1404.     * This method creates the archive file and add the files / directories
  1405.     * that are listed in $p_filelist.
  1406.     * If a file with the same name exist and is writable, it is replaced
  1407.     * by the new tar.
  1408.     * The method return false and a PEAR error text.
  1409.     * The $p_filelist parameter can be an array of string, each string
  1410.     * representing a filename or a directory name with their path if
  1411.     * needed. It can also be a single string with names separated by a
  1412.     * single blank.
  1413.     * For each directory added in the archive, the files and
  1414.     * sub-directories are also added.
  1415.     * See also createModify() method for more details.
  1416.     *
  1417.     * @param array  $p_filelist An array of filenames and directory names, or a
  1418.     *                           single string with names separated by a single
  1419.     *                           blank space.
  1420.     * @return                   true on success, false on error.
  1421.     * @see createModify()
  1422.     * @access public
  1423.     */
  1424.     function create($p_filelist)
  1425.     {
  1426.         return $this->createModify($p_filelist, '', '');
  1427.     }
  1428.     // }}}
  1429.  
  1430.     // {{{ add()
  1431.     /**
  1432.     * This method add the files / directories that are listed in $p_filelist in
  1433.     * the archive. If the archive does not exist it is created.
  1434.     * The method return false and a PEAR error text.
  1435.     * The files and directories listed are only added at the end of the archive,
  1436.     * even if a file with the same name is already archived.
  1437.     * See also createModify() method for more details.
  1438.     *
  1439.     * @param array  $p_filelist An array of filenames and directory names, or a
  1440.     *                           single string with names separated by a single
  1441.     *                           blank space.
  1442.     * @return                   true on success, false on error.
  1443.     * @see createModify()
  1444.     * @access public
  1445.     */
  1446.     function add($p_filelist)
  1447.     {
  1448.         return $this->addModify($p_filelist, '', '');
  1449.     }
  1450.     // }}}
  1451.  
  1452.     // {{{ extract()
  1453.     function extract($p_path='')
  1454.     {
  1455.         return $this->extractModify($p_path, '');
  1456.     }
  1457.     // }}}
  1458.  
  1459.     // {{{ listContent()
  1460.     function listContent()
  1461.     {
  1462.         $v_list_detail = array();
  1463.  
  1464.         if ($this->_openRead()) {
  1465.             if (!$this->_extractList('', $v_list_detail, "list", '', '')) {
  1466.                 unset($v_list_detail);
  1467.                 $v_list_detail = 0;
  1468.             }
  1469.             $this->_close();
  1470.         }
  1471.  
  1472.         return $v_list_detail;
  1473.     }
  1474.     // }}}
  1475.  
  1476.     // {{{ createModify()
  1477.     /**
  1478.     * This method creates the archive file and add the files / directories
  1479.     * that are listed in $p_filelist.
  1480.     * If the file already exists and is writable, it is replaced by the
  1481.     * new tar. It is a create and not an add. If the file exists and is
  1482.     * read-only or is a directory it is not replaced. The method return
  1483.     * false and a PEAR error text.
  1484.     * The $p_filelist parameter can be an array of string, each string
  1485.     * representing a filename or a directory name with their path if
  1486.     * needed. It can also be a single string with names separated by a
  1487.     * single blank.
  1488.     * The path indicated in $p_remove_dir will be removed from the
  1489.     * memorized path of each file / directory listed when this path
  1490.     * exists. By default nothing is removed (empty path '')
  1491.     * The path indicated in $p_add_dir will be added at the beginning of
  1492.     * the memorized path of each file / directory listed. However it can
  1493.     * be set to empty ''. The adding of a path is done after the removing
  1494.     * of path.
  1495.     * The path add/remove ability enables the user to prepare an archive
  1496.     * for extraction in a different path than the origin files are.
  1497.     * See also addModify() method for file adding properties.
  1498.     *
  1499.     * @param array  $p_filelist     An array of filenames and directory names,
  1500.     *                               or a single string with names separated by
  1501.     *                               a single blank space.
  1502.     * @param string $p_add_dir      A string which contains a path to be added
  1503.     *                               to the memorized path of each element in
  1504.     *                               the list.
  1505.     * @param string $p_remove_dir   A string which contains a path to be
  1506.     *                               removed from the memorized path of each
  1507.     *                               element in the list, when relevant.
  1508.     * @return boolean               true on success, false on error.
  1509.     * @access public
  1510.     * @see addModify()
  1511.     */
  1512.     function createModify($p_filelist, $p_add_dir, $p_remove_dir='')
  1513.     {
  1514.         $v_result = true;
  1515.  
  1516.         if (!$this->_openWrite())
  1517.             return false;
  1518.  
  1519.         if ($p_filelist != '') {
  1520.             if (is_array($p_filelist))
  1521.                 $v_list = $p_filelist;
  1522.             elseif (is_string($p_filelist))
  1523.                 $v_list = explode($this->_separator, $p_filelist);
  1524.             else {
  1525.                 $this->_cleanFile();
  1526.                 $this->_error('Invalid file list');
  1527.                 return false;
  1528.             }
  1529.  
  1530.             $v_result = $this->_addList($v_list, $p_add_dir, $p_remove_dir);
  1531.         }
  1532.  
  1533.         if ($v_result) {
  1534.             $this->_writeFooter();
  1535.             $this->_close();
  1536.         } else
  1537.             $this->_cleanFile();
  1538.  
  1539.         return $v_result;
  1540.     }
  1541.     // }}}
  1542.  
  1543.     // {{{ addModify()
  1544.     /**
  1545.     * This method add the files / directories listed in $p_filelist at the
  1546.     * end of the existing archive. If the archive does not yet exists it
  1547.     * is created.
  1548.     * The $p_filelist parameter can be an array of string, each string
  1549.     * representing a filename or a directory name with their path if
  1550.     * needed. It can also be a single string with names separated by a
  1551.     * single blank.
  1552.     * The path indicated in $p_remove_dir will be removed from the
  1553.     * memorized path of each file / directory listed when this path
  1554.     * exists. By default nothing is removed (empty path '')
  1555.     * The path indicated in $p_add_dir will be added at the beginning of
  1556.     * the memorized path of each file / directory listed. However it can
  1557.     * be set to empty ''. The adding of a path is done after the removing
  1558.     * of path.
  1559.     * The path add/remove ability enables the user to prepare an archive
  1560.     * for extraction in a different path than the origin files are.
  1561.     * If a file/dir is already in the archive it will only be added at the
  1562.     * end of the archive. There is no update of the existing archived
  1563.     * file/dir. However while extracting the archive, the last file will
  1564.     * replace the first one. This results in a none optimization of the
  1565.     * archive size.
  1566.     * If a file/dir does not exist the file/dir is ignored. However an
  1567.     * error text is send to PEAR error.
  1568.     * If a file/dir is not readable the file/dir is ignored. However an
  1569.     * error text is send to PEAR error.
  1570.     *
  1571.     * @param array      $p_filelist     An array of filenames and directory
  1572.     *                                   names, or a single string with names
  1573.     *                                   separated by a single blank space.
  1574.     * @param string     $p_add_dir      A string which contains a path to be
  1575.     *                                   added to the memorized path of each
  1576.     *                                   element in the list.
  1577.     * @param string     $p_remove_dir   A string which contains a path to be
  1578.     *                                   removed from the memorized path of
  1579.     *                                   each element in the list, when
  1580.     *                                   relevant.
  1581.     * @return                           true on success, false on error.
  1582.     * @access public
  1583.     */
  1584.     function addModify($p_filelist, $p_add_dir, $p_remove_dir='')
  1585.     {
  1586.         $v_result = true;
  1587.  
  1588.         if (!$this->_isArchive())
  1589.             $v_result = $this->createModify($p_filelist, $p_add_dir,
  1590.                                             $p_remove_dir);
  1591.         else {
  1592.             if (is_array($p_filelist))
  1593.                 $v_list = $p_filelist;
  1594.             elseif (is_string($p_filelist))
  1595.                 $v_list = explode($this->_separator, $p_filelist);
  1596.             else {
  1597.                 $this->_error('Invalid file list');
  1598.                 return false;
  1599.             }
  1600.  
  1601.             $v_result = $this->_append($v_list, $p_add_dir, $p_remove_dir);
  1602.         }
  1603.  
  1604.         return $v_result;
  1605.     }
  1606.     // }}}
  1607.  
  1608.     // {{{ addString()
  1609.     /**
  1610.     * This method add a single string as a file at the
  1611.     * end of the existing archive. If the archive does not yet exists it
  1612.     * is created.
  1613.     *
  1614.     * @param string     $p_filename     A string which contains the full
  1615.     *                                   filename path that will be associated
  1616.     *                                   with the string.
  1617.     * @param string     $p_string       The content of the file added in
  1618.     *                                   the archive.
  1619.     * @return                           true on success, false on error.
  1620.     * @access public
  1621.     */
  1622.     function addString($p_filename, $p_string)
  1623.     {
  1624.         $v_result = true;
  1625.         
  1626.         if (!$this->_isArchive()) {
  1627.             if (!$this->_openWrite()) {
  1628.                 return false;
  1629.             }
  1630.             $this->_close();
  1631.         }
  1632.         
  1633.         if (!$this->_openAppend())
  1634.             return false;
  1635.  
  1636.         // Need to check the get back to the temporary file ? ....
  1637.         $v_result = $this->_addString($p_filename, $p_string);
  1638.  
  1639.         $this->_writeFooter();
  1640.  
  1641.         $this->_close();
  1642.  
  1643.         return $v_result;
  1644.     }
  1645.     // }}}
  1646.  
  1647.     // {{{ extractModify()
  1648.     /**
  1649.     * This method extract all the content of the archive in the directory
  1650.     * indicated by $p_path. When relevant the memorized path of the
  1651.     * files/dir can be modified by removing the $p_remove_path path at the
  1652.     * beginning of the file/dir path.
  1653.     * While extracting a file, if the directory path does not exists it is
  1654.     * created.
  1655.     * While extracting a file, if the file already exists it is replaced
  1656.     * without looking for last modification date.
  1657.     * While extracting a file, if the file already exists and is write
  1658.     * protected, the extraction is aborted.
  1659.     * While extracting a file, if a directory with the same name already
  1660.     * exists, the extraction is aborted.
  1661.     * While extracting a directory, if a file with the same name already
  1662.     * exists, the extraction is aborted.
  1663.     * While extracting a file/directory if the destination directory exist
  1664.     * and is write protected, or does not exist but can not be created,
  1665.     * the extraction is aborted.
  1666.     * If after extraction an extracted file does not show the correct
  1667.     * stored file size, the extraction is aborted.
  1668.     * When the extraction is aborted, a PEAR error text is set and false
  1669.     * is returned. However the result can be a partial extraction that may
  1670.     * need to be manually cleaned.
  1671.     *
  1672.     * @param string $p_path         The path of the directory where the
  1673.     *                               files/dir need to by extracted.
  1674.     * @param string $p_remove_path  Part of the memorized path that can be
  1675.     *                               removed if present at the beginning of
  1676.     *                               the file/dir path.
  1677.     * @return boolean               true on success, false on error.
  1678.     * @access public
  1679.     * @see extractList()
  1680.     */
  1681.     function extractModify($p_path, $p_remove_path)
  1682.     {
  1683.         $v_result = true;
  1684.         $v_list_detail = array();
  1685.  
  1686.         if ($v_result = $this->_openRead()) {
  1687.             $v_result = $this->_extractList($p_path, $v_list_detail,
  1688.                                             "complete", 0, $p_remove_path);
  1689.             $this->_close();
  1690.         }
  1691.  
  1692.         return $v_result;
  1693.     }
  1694.     // }}}
  1695.  
  1696.     // {{{ extractInString()
  1697.     /**
  1698.     * This method extract from the archive one file identified by $p_filename.
  1699.     * The return value is a string with the file content, or NULL on error.
  1700.     * @param string $p_filename     The path of the file to extract in a string.
  1701.     * @return                       a string with the file content or NULL.
  1702.     * @access public
  1703.     */
  1704.     function extractInString($p_filename)
  1705.     {
  1706.         if ($this->_openRead()) {
  1707.             $v_result = $this->_extractInString($p_filename);
  1708.             $this->_close();
  1709.         } else {
  1710.             $v_result = NULL;
  1711.         }
  1712.  
  1713.         return $v_result;
  1714.     }
  1715.     // }}}
  1716.  
  1717.     // {{{ extractList()
  1718.     /**
  1719.     * This method extract from the archive only the files indicated in the
  1720.     * $p_filelist. These files are extracted in the current directory or
  1721.     * in the directory indicated by the optional $p_path parameter.
  1722.     * If indicated the $p_remove_path can be used in the same way as it is
  1723.     * used in extractModify() method.
  1724.     * @param array  $p_filelist     An array of filenames and directory names,
  1725.     *                               or a single string with names separated
  1726.     *                               by a single blank space.
  1727.     * @param string $p_path         The path of the directory where the
  1728.     *                               files/dir need to by extracted.
  1729.     * @param string $p_remove_path  Part of the memorized path that can be
  1730.     *                               removed if present at the beginning of
  1731.     *                               the file/dir path.
  1732.     * @return                       true on success, false on error.
  1733.     * @access public
  1734.     * @see extractModify()
  1735.     */
  1736.     function extractList($p_filelist, $p_path='', $p_remove_path='')
  1737.     {
  1738.         $v_result = true;
  1739.         $v_list_detail = array();
  1740.  
  1741.         if (is_array($p_filelist))
  1742.             $v_list = $p_filelist;
  1743.         elseif (is_string($p_filelist))
  1744.             $v_list = explode($this->_separator, $p_filelist);
  1745.         else {
  1746.             $this->_error('Invalid string list');
  1747.             return false;
  1748.         }
  1749.  
  1750.         if ($v_result = $this->_openRead()) {
  1751.             $v_result = $this->_extractList($p_path, $v_list_detail, "partial",
  1752.                                             $v_list, $p_remove_path);
  1753.             $this->_close();
  1754.         }
  1755.  
  1756.         return $v_result;
  1757.     }
  1758.     // }}}
  1759.  
  1760.     // {{{ setAttribute()
  1761.     /**
  1762.     * This method set specific attributes of the archive. It uses a variable
  1763.     * list of parameters, in the format attribute code + attribute values :
  1764.     * $arch->setAttribute(ARCHIVE_TAR_ATT_SEPARATOR, ',');
  1765.     * @param mixed $argv            variable list of attributes and values
  1766.     * @return                       true on success, false on error.
  1767.     * @access public
  1768.     */
  1769.     function setAttribute()
  1770.     {
  1771.         $v_result = true;
  1772.         
  1773.         // ----- Get the number of variable list of arguments
  1774.         if (($v_size = func_num_args()) == 0) {
  1775.             return true;
  1776.         }
  1777.         
  1778.         // ----- Get the arguments
  1779.         $v_att_list = &func_get_args();
  1780.  
  1781.         // ----- Read the attributes
  1782.         $i=0;
  1783.         while ($i<$v_size) {
  1784.  
  1785.             // ----- Look for next option
  1786.             switch ($v_att_list[$i]) {
  1787.                 // ----- Look for options that request a string value
  1788.                 case ARCHIVE_TAR_ATT_SEPARATOR :
  1789.                     // ----- Check the number of parameters
  1790.                     if (($i+1) >= $v_size) {
  1791.                         $this->_error('Invalid number of parameters for '
  1792.                                       .'attribute ARCHIVE_TAR_ATT_SEPARATOR');
  1793.                         return false;
  1794.                     }
  1795.  
  1796.                     // ----- Get the value
  1797.                     $this->_separator = $v_att_list[$i+1];
  1798.                     $i++;
  1799.                 break;
  1800.  
  1801.                 default :
  1802.                     $this->_error('Unknow attribute code '.$v_att_list[$i].'');
  1803.                     return false;
  1804.             }
  1805.  
  1806.             // ----- Next attribute
  1807.             $i++;
  1808.         }
  1809.  
  1810.         return $v_result;
  1811.     }
  1812.     // }}}
  1813.  
  1814.     // {{{ _error()
  1815.     function _error($p_message)
  1816.     {
  1817.         // ----- To be completed
  1818.         $this->raiseError($p_message);
  1819.     }
  1820.     // }}}
  1821.  
  1822.     // {{{ _warning()
  1823.     function _warning($p_message)
  1824.     {
  1825.         // ----- To be completed
  1826.         $this->raiseError($p_message);
  1827.     }
  1828.     // }}}
  1829.  
  1830.     // {{{ _isArchive()
  1831.     function _isArchive($p_filename=NULL)
  1832.     {
  1833.         if ($p_filename == NULL) {
  1834.             $p_filename = $this->_tarname;
  1835.         }
  1836.         clearstatcache();
  1837.         return @is_file($p_filename);
  1838.     }
  1839.     // }}}
  1840.  
  1841.     // {{{ _openWrite()
  1842.     function _openWrite()
  1843.     {
  1844.         if ($this->_compress_type == 'gz')
  1845.             $this->_file = @gzopen($this->_tarname, "wb9");
  1846.         else if ($this->_compress_type == 'bz2')
  1847.             $this->_file = @bzopen($this->_tarname, "wb");
  1848.         else if ($this->_compress_type == 'none')
  1849.             $this->_file = @fopen($this->_tarname, "wb");
  1850.         else
  1851.             $this->_error('Unknown or missing compression type ('
  1852.                           .$this->_compress_type.')');
  1853.  
  1854.         if ($this->_file == 0) {
  1855.             $this->_error('Unable to open in write mode \''
  1856.                           .$this->_tarname.'\'');
  1857.             return false;
  1858.         }
  1859.  
  1860.         return true;
  1861.     }
  1862.     // }}}
  1863.  
  1864.     // {{{ _openRead()
  1865.     function _openRead()
  1866.     {
  1867.         if (strtolower(substr($this->_tarname, 0, 7)) == 'http://') {
  1868.  
  1869.           // ----- Look if a local copy need to be done
  1870.           if ($this->_temp_tarname == '') {
  1871.               $this->_temp_tarname = uniqid('tar').'.tmp';
  1872.               if (!$v_file_from = @fopen($this->_tarname, 'rb')) {
  1873.                 $this->_error('Unable to open in read mode \''
  1874.                               .$this->_tarname.'\'');
  1875.                 $this->_temp_tarname = '';
  1876.                 return false;
  1877.               }
  1878.               if (!$v_file_to = @fopen($this->_temp_tarname, 'wb')) {
  1879.                 $this->_error('Unable to open in write mode \''
  1880.                               .$this->_temp_tarname.'\'');
  1881.                 $this->_temp_tarname = '';
  1882.                 return false;
  1883.               }
  1884.               while ($v_data = @fread($v_file_from, 1024))
  1885.                   @fwrite($v_file_to, $v_data);
  1886.               @fclose($v_file_from);
  1887.               @fclose($v_file_to);
  1888.           }
  1889.  
  1890.           // ----- File to open if the local copy
  1891.           $v_filename = $this->_temp_tarname;
  1892.  
  1893.         } else
  1894.           // ----- File to open if the normal Tar file
  1895.           $v_filename = $this->_tarname;
  1896.  
  1897.         if ($this->_compress_type == 'gz')
  1898.             $this->_file = @gzopen($v_filename, "rb");
  1899.         else if ($this->_compress_type == 'bz2')
  1900.             $this->_file = @bzopen($v_filename, "rb");
  1901.         else if ($this->_compress_type == 'none')
  1902.             $this->_file = @fopen($v_filename, "rb");
  1903.         else
  1904.             $this->_error('Unknown or missing compression type ('
  1905.                           .$this->_compress_type.')');
  1906.  
  1907.         if ($this->_file == 0) {
  1908.             $this->_error('Unable to open in read mode \''.$v_filename.'\'');
  1909.             return false;
  1910.         }
  1911.  
  1912.         return true;
  1913.     }
  1914.     // }}}
  1915.  
  1916.     // {{{ _openReadWrite()
  1917.     function _openReadWrite()
  1918.     {
  1919.         if ($this->_compress_type == 'gz')
  1920.             $this->_file = @gzopen($this->_tarname, "r+b");
  1921.         else if ($this->_compress_type == 'bz2')
  1922.             $this->_file = @bzopen($this->_tarname, "r+b");
  1923.         else if ($this->_compress_type == 'none')
  1924.             $this->_file = @fopen($this->_tarname, "r+b");
  1925.         else
  1926.             $this->_error('Unknown or missing compression type ('
  1927.                           .$this->_compress_type.')');
  1928.  
  1929.         if ($this->_file == 0) {
  1930.             $this->_error('Unable to open in read/write mode \''
  1931.                           .$this->_tarname.'\'');
  1932.             return false;
  1933.         }
  1934.  
  1935.         return true;
  1936.     }
  1937.     // }}}
  1938.  
  1939.     // {{{ _close()
  1940.     function _close()
  1941.     {
  1942.         //if (isset($this->_file)) {
  1943.         if (is_resource($this->_file)) {
  1944.             if ($this->_compress_type == 'gz')
  1945.                 @gzclose($this->_file);
  1946.             else if ($this->_compress_type == 'bz2')
  1947.                 @bzclose($this->_file);
  1948.             else if ($this->_compress_type == 'none')
  1949.                 @fclose($this->_file);
  1950.             else
  1951.                 $this->_error('Unknown or missing compression type ('
  1952.                               .$this->_compress_type.')');
  1953.  
  1954.             $this->_file = 0;
  1955.         }
  1956.  
  1957.         // ----- Look if a local copy need to be erase
  1958.         // Note that it might be interesting to keep the url for a time : ToDo
  1959.         if ($this->_temp_tarname != '') {
  1960.             @unlink($this->_temp_tarname);
  1961.             $this->_temp_tarname = '';
  1962.         }
  1963.  
  1964.         return true;
  1965.     }
  1966.     // }}}
  1967.  
  1968.     // {{{ _cleanFile()
  1969.     function _cleanFile()
  1970.     {
  1971.         $this->_close();
  1972.  
  1973.         // ----- Look for a local copy
  1974.         if ($this->_temp_tarname != '') {
  1975.             // ----- Remove the local copy but not the remote tarname
  1976.             @unlink($this->_temp_tarname);
  1977.             $this->_temp_tarname = '';
  1978.         } else {
  1979.             // ----- Remove the local tarname file
  1980.             @unlink($this->_tarname);
  1981.         }
  1982.         $this->_tarname = '';
  1983.  
  1984.         return true;
  1985.     }
  1986.     // }}}
  1987.  
  1988.     // {{{ _writeBlock()
  1989.     function _writeBlock($p_binary_data, $p_len=null)
  1990.     {
  1991.       if (is_resource($this->_file)) {
  1992.           if ($p_len === null) {
  1993.               if ($this->_compress_type == 'gz')
  1994.                   @gzputs($this->_file, $p_binary_data);
  1995.               else if ($this->_compress_type == 'bz2')
  1996.                   @bzwrite($this->_file, $p_binary_data);
  1997.               else if ($this->_compress_type == 'none')
  1998.                   @fputs($this->_file, $p_binary_data);
  1999.               else
  2000.                   $this->_error('Unknown or missing compression type ('
  2001.                                 .$this->_compress_type.')');
  2002.           } else {
  2003.               if ($this->_compress_type == 'gz')
  2004.                   @gzputs($this->_file, $p_binary_data, $p_len);
  2005.               else if ($this->_compress_type == 'bz2')
  2006.                   @bzwrite($this->_file, $p_binary_data, $p_len);
  2007.               else if ($this->_compress_type == 'none')
  2008.                   @fputs($this->_file, $p_binary_data, $p_len);
  2009.               else
  2010.                   $this->_error('Unknown or missing compression type ('
  2011.                                 .$this->_compress_type.')');
  2012.  
  2013.           }
  2014.       }
  2015.       return true;
  2016.     }
  2017.     // }}}
  2018.  
  2019.     // {{{ _readBlock()
  2020.     function _readBlock()
  2021.     {
  2022.       $v_block = null;
  2023.       if (is_resource($this->_file)) {
  2024.           if ($this->_compress_type == 'gz')
  2025.               $v_block = @gzread($this->_file, 512);
  2026.           else if ($this->_compress_type == 'bz2')
  2027.               $v_block = @bzread($this->_file, 512);
  2028.           else if ($this->_compress_type == 'none')
  2029.               $v_block = @fread($this->_file, 512);
  2030.           else
  2031.               $this->_error('Unknown or missing compression type ('
  2032.                             .$this->_compress_type.')');
  2033.       }
  2034.       return $v_block;
  2035.     }
  2036.     // }}}
  2037.  
  2038.     // {{{ _jumpBlock()
  2039.     function _jumpBlock($p_len=null)
  2040.     {
  2041.       if (is_resource($this->_file)) {
  2042.           if ($p_len === null)
  2043.               $p_len = 1;
  2044.  
  2045.           if ($this->_compress_type == 'gz') {
  2046.               @gzseek($this->_file, gztell($this->_file)+($p_len*512));
  2047.           }
  2048.           else if ($this->_compress_type == 'bz2') {
  2049.               // ----- Replace missing bztell() and bzseek()
  2050.               for ($i=0; $i<$p_len; $i++)
  2051.                   $this->_readBlock();
  2052.           } else if ($this->_compress_type == 'none')
  2053.               @fseek($this->_file, ftell($this->_file)+($p_len*512));
  2054.           else
  2055.               $this->_error('Unknown or missing compression type ('
  2056.                             .$this->_compress_type.')');
  2057.  
  2058.       }
  2059.       return true;
  2060.     }
  2061.     // }}}
  2062.  
  2063.     // {{{ _writeFooter()
  2064.     function _writeFooter()
  2065.     {
  2066.       if (is_resource($this->_file)) {
  2067.           // ----- Write the last 0 filled block for end of archive
  2068.           $v_binary_data = pack('a1024', '');
  2069.           $this->_writeBlock($v_binary_data);
  2070.       }
  2071.       return true;
  2072.     }
  2073.     // }}}
  2074.  
  2075.     // {{{ _addList()
  2076.     function _addList($p_list, $p_add_dir, $p_remove_dir)
  2077.     {
  2078.       $v_result=true;
  2079.       $v_header = array();
  2080.  
  2081.       // ----- Remove potential windows directory separator
  2082.       $p_add_dir = $this->_translateWinPath($p_add_dir);
  2083.       $p_remove_dir = $this->_translateWinPath($p_remove_dir, false);
  2084.  
  2085.       if (!$this->_file) {
  2086.           $this->_error('Invalid file descriptor');
  2087.           return false;
  2088.       }
  2089.  
  2090.       if (sizeof($p_list) == 0)
  2091.           return true;
  2092.  
  2093.       foreach ($p_list as $v_filename) {
  2094.           if (!$v_result) {
  2095.               break;
  2096.           }
  2097.  
  2098.         // ----- Skip the current tar name
  2099.         if ($v_filename == $this->_tarname)
  2100.             continue;
  2101.  
  2102.         if ($v_filename == '')
  2103.             continue;
  2104.  
  2105.         if (!file_exists($v_filename)) {
  2106.             $this->_warning("File '$v_filename' does not exist");
  2107.             continue;
  2108.         }
  2109.  
  2110.         // ----- Add the file or directory header
  2111.         if (!$this->_addFile($v_filename, $v_header, $p_add_dir, $p_remove_dir))
  2112.             return false;
  2113.  
  2114.         if (@is_dir($v_filename)) {
  2115.             if (!($p_hdir = opendir($v_filename))) {
  2116.                 $this->_warning("Directory '$v_filename' can not be read");
  2117.                 continue;
  2118.             }
  2119.             while (false !== ($p_hitem = readdir($p_hdir))) {
  2120.                 if (($p_hitem != '.') && ($p_hitem != '..')) {
  2121.                     if ($v_filename != ".")
  2122.                         $p_temp_list[0] = $v_filename.'/'.$p_hitem;
  2123.                     else
  2124.                         $p_temp_list[0] = $p_hitem;
  2125.  
  2126.                     $v_result = $this->_addList($p_temp_list,
  2127.                                                 $p_add_dir,
  2128.                                                 $p_remove_dir);
  2129.                 }
  2130.             }
  2131.  
  2132.             unset($p_temp_list);
  2133.             unset($p_hdir);
  2134.             unset($p_hitem);
  2135.         }
  2136.       }
  2137.  
  2138.       return $v_result;
  2139.     }
  2140.     // }}}
  2141.  
  2142.     // {{{ _addFile()
  2143.     function _addFile($p_filename, &$p_header, $p_add_dir, $p_remove_dir)
  2144.     {
  2145.       if (!$this->_file) {
  2146.           $this->_error('Invalid file descriptor');
  2147.           return false;
  2148.       }
  2149.  
  2150.       if ($p_filename == '') {
  2151.           $this->_error('Invalid file name');
  2152.           return false;
  2153.       }
  2154.  
  2155.       // ----- Calculate the stored filename
  2156.       $p_filename = $this->_translateWinPath($p_filename, false);;
  2157.       $v_stored_filename = $p_filename;
  2158.       if (strcmp($p_filename, $p_remove_dir) == 0) {
  2159.           return true;
  2160.       }
  2161.       if ($p_remove_dir != '') {
  2162.           if (substr($p_remove_dir, -1) != '/')
  2163.               $p_remove_dir .= '/';
  2164.  
  2165.           if (substr($p_filename, 0, strlen($p_remove_dir)) == $p_remove_dir)
  2166.               $v_stored_filename = substr($p_filename, strlen($p_remove_dir));
  2167.       }
  2168.       $v_stored_filename = $this->_translateWinPath($v_stored_filename);
  2169.       if ($p_add_dir != '') {
  2170.           if (substr($p_add_dir, -1) == '/')
  2171.               $v_stored_filename = $p_add_dir.$v_stored_filename;
  2172.           else
  2173.               $v_stored_filename = $p_add_dir.'/'.$v_stored_filename;
  2174.       }
  2175.  
  2176.       $v_stored_filename = $this->_pathReduction($v_stored_filename);
  2177.  
  2178.       if ($this->_isArchive($p_filename)) {
  2179.           if (($v_file = @fopen($p_filename, "rb")) == 0) {
  2180.               $this->_warning("Unable to open file '".$p_filename
  2181.                               ."' in binary read mode");
  2182.               return true;
  2183.           }
  2184.  
  2185.           if (!$this->_writeHeader($p_filename, $v_stored_filename))
  2186.               return false;
  2187.  
  2188.           while (($v_buffer = fread($v_file, 512)) != '') {
  2189.               $v_binary_data = pack("a512", "$v_buffer");
  2190.               $this->_writeBlock($v_binary_data);
  2191.           }
  2192.  
  2193.           fclose($v_file);
  2194.  
  2195.       } else {
  2196.           // ----- Only header for dir
  2197.           if (!$this->_writeHeader($p_filename, $v_stored_filename))
  2198.               return false;
  2199.       }
  2200.  
  2201.       return true;
  2202.     }
  2203.     // }}}
  2204.  
  2205.     // {{{ _addString()
  2206.     function _addString($p_filename, $p_string)
  2207.     {
  2208.       if (!$this->_file) {
  2209.           $this->_error('Invalid file descriptor');
  2210.           return false;
  2211.       }
  2212.  
  2213.       if ($p_filename == '') {
  2214.           $this->_error('Invalid file name');
  2215.           return false;
  2216.       }
  2217.  
  2218.       // ----- Calculate the stored filename
  2219.       $p_filename = $this->_translateWinPath($p_filename, false);;
  2220.  
  2221.       if (!$this->_writeHeaderBlock($p_filename, strlen($p_string),
  2222.                                       time(), 384, "", 0, 0))
  2223.           return false;
  2224.  
  2225.       $i=0;
  2226.       while (($v_buffer = substr($p_string, (($i++)*512), 512)) != '') {
  2227.           $v_binary_data = pack("a512", $v_buffer);
  2228.           $this->_writeBlock($v_binary_data);
  2229.       }
  2230.  
  2231.       return true;
  2232.     }
  2233.     // }}}
  2234.  
  2235.     // {{{ _writeHeader()
  2236.     function _writeHeader($p_filename, $p_stored_filename)
  2237.     {
  2238.         if ($p_stored_filename == '')
  2239.             $p_stored_filename = $p_filename;
  2240.         $v_reduce_filename = $this->_pathReduction($p_stored_filename);
  2241.  
  2242.         if (strlen($v_reduce_filename) > 99) {
  2243.           if (!$this->_writeLongHeader($v_reduce_filename))
  2244.             return false;
  2245.         }
  2246.  
  2247.         $v_info = stat($p_filename);
  2248.         $v_uid = sprintf("%6s ", DecOct($v_info[4]));
  2249.         $v_gid = sprintf("%6s ", DecOct($v_info[5]));
  2250.         $v_perms = sprintf("%6s ", DecOct(fileperms($p_filename)));
  2251.  
  2252.         $v_mtime = sprintf("%11s", DecOct(filemtime($p_filename)));
  2253.  
  2254.         if (@is_dir($p_filename)) {
  2255.           $v_typeflag = "5";
  2256.           $v_size = sprintf("%11s ", DecOct(0));
  2257.         } else {
  2258.           $v_typeflag = '';
  2259.           clearstatcache();
  2260.           $v_size = sprintf("%11s ", DecOct(filesize($p_filename)));
  2261.         }
  2262.  
  2263.         $v_linkname = '';
  2264.  
  2265.         $v_magic = '';
  2266.  
  2267.         $v_version = '';
  2268.  
  2269.         $v_uname = '';
  2270.  
  2271.         $v_gname = '';
  2272.  
  2273.         $v_devmajor = '';
  2274.  
  2275.         $v_devminor = '';
  2276.  
  2277.         $v_prefix = '';
  2278.  
  2279.         $v_binary_data_first = pack("a100a8a8a8a12A12",
  2280.                                     $v_reduce_filename, $v_perms, $v_uid,
  2281.                                     $v_gid, $v_size, $v_mtime);
  2282.         $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12",
  2283.                                    $v_typeflag, $v_linkname, $v_magic,
  2284.                                    $v_version, $v_uname, $v_gname,
  2285.                                    $v_devmajor, $v_devminor, $v_prefix, '');
  2286.  
  2287.         // ----- Calculate the checksum
  2288.         $v_checksum = 0;
  2289.         // ..... First part of the header
  2290.         for ($i=0; $i<148; $i++)
  2291.             $v_checksum += ord(substr($v_binary_data_first,$i,1));
  2292.         // ..... Ignore the checksum value and replace it by ' ' (space)
  2293.         for ($i=148; $i<156; $i++)
  2294.             $v_checksum += ord(' ');
  2295.         // ..... Last part of the header
  2296.         for ($i=156, $j=0; $i<512; $i++, $j++)
  2297.             $v_checksum += ord(substr($v_binary_data_last,$j,1));
  2298.  
  2299.         // ----- Write the first 148 bytes of the header in the archive
  2300.         $this->_writeBlock($v_binary_data_first, 148);
  2301.  
  2302.         // ----- Write the calculated checksum
  2303.         $v_checksum = sprintf("%6s ", DecOct($v_checksum));
  2304.         $v_binary_data = pack("a8", $v_checksum);
  2305.         $this->_writeBlock($v_binary_data, 8);
  2306.  
  2307.         // ----- Write the last 356 bytes of the header in the archive
  2308.         $this->_writeBlock($v_binary_data_last, 356);
  2309.  
  2310.         return true;
  2311.     }
  2312.     // }}}
  2313.  
  2314.     // {{{ _writeHeaderBlock()
  2315.     function _writeHeaderBlock($p_filename, $p_size, $p_mtime=0, $p_perms=0,
  2316.                                $p_type='', $p_uid=0, $p_gid=0)
  2317.     {
  2318.         $p_filename = $this->_pathReduction($p_filename);
  2319.  
  2320.         if (strlen($p_filename) > 99) {
  2321.           if (!$this->_writeLongHeader($p_filename))
  2322.             return false;
  2323.         }
  2324.  
  2325.         if ($p_type == "5") {
  2326.           $v_size = sprintf("%11s ", DecOct(0));
  2327.         } else {
  2328.           $v_size = sprintf("%11s ", DecOct($p_size));
  2329.         }
  2330.  
  2331.         $v_uid = sprintf("%6s ", DecOct($p_uid));
  2332.         $v_gid = sprintf("%6s ", DecOct($p_gid));
  2333.         $v_perms = sprintf("%6s ", DecOct($p_perms));
  2334.  
  2335.         $v_mtime = sprintf("%11s", DecOct($p_mtime));
  2336.  
  2337.         $v_linkname = '';
  2338.  
  2339.         $v_magic = '';
  2340.  
  2341.         $v_version = '';
  2342.  
  2343.         $v_uname = '';
  2344.  
  2345.         $v_gname = '';
  2346.  
  2347.         $v_devmajor = '';
  2348.  
  2349.         $v_devminor = '';
  2350.  
  2351.         $v_prefix = '';
  2352.  
  2353.         $v_binary_data_first = pack("a100a8a8a8a12A12",
  2354.                                     $p_filename, $v_perms, $v_uid, $v_gid,
  2355.                                     $v_size, $v_mtime);
  2356.         $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12",
  2357.                                    $p_type, $v_linkname, $v_magic,
  2358.                                    $v_version, $v_uname, $v_gname,
  2359.                                    $v_devmajor, $v_devminor, $v_prefix, '');
  2360.  
  2361.         // ----- Calculate the checksum
  2362.         $v_checksum = 0;
  2363.         // ..... First part of the header
  2364.         for ($i=0; $i<148; $i++)
  2365.             $v_checksum += ord(substr($v_binary_data_first,$i,1));
  2366.         // ..... Ignore the checksum value and replace it by ' ' (space)
  2367.         for ($i=148; $i<156; $i++)
  2368.             $v_checksum += ord(' ');
  2369.         // ..... Last part of the header
  2370.         for ($i=156, $j=0; $i<512; $i++, $j++)
  2371.             $v_checksum += ord(substr($v_binary_data_last,$j,1));
  2372.  
  2373.         // ----- Write the first 148 bytes of the header in the archive
  2374.         $this->_writeBlock($v_binary_data_first, 148);
  2375.  
  2376.         // ----- Write the calculated checksum
  2377.         $v_checksum = sprintf("%6s ", DecOct($v_checksum));
  2378.         $v_binary_data = pack("a8", $v_checksum);
  2379.         $this->_writeBlock($v_binary_data, 8);
  2380.  
  2381.         // ----- Write the last 356 bytes of the header in the archive
  2382.         $this->_writeBlock($v_binary_data_last, 356);
  2383.  
  2384.         return true;
  2385.     }
  2386.     // }}}
  2387.  
  2388.     // {{{ _writeLongHeader()
  2389.     function _writeLongHeader($p_filename)
  2390.     {
  2391.         $v_size = sprintf("%11s ", DecOct(strlen($p_filename)));
  2392.  
  2393.         $v_typeflag = 'L';
  2394.  
  2395.         $v_linkname = '';
  2396.  
  2397.         $v_magic = '';
  2398.  
  2399.         $v_version = '';
  2400.  
  2401.         $v_uname = '';
  2402.  
  2403.         $v_gname = '';
  2404.  
  2405.         $v_devmajor = '';
  2406.  
  2407.         $v_devminor = '';
  2408.  
  2409.         $v_prefix = '';
  2410.  
  2411.         $v_binary_data_first = pack("a100a8a8a8a12A12",
  2412.                                     '././@LongLink', 0, 0, 0, $v_size, 0);
  2413.         $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12",
  2414.                                    $v_typeflag, $v_linkname, $v_magic,
  2415.                                    $v_version, $v_uname, $v_gname,
  2416.                                    $v_devmajor, $v_devminor, $v_prefix, '');
  2417.  
  2418.         // ----- Calculate the checksum
  2419.         $v_checksum = 0;
  2420.         // ..... First part of the header
  2421.         for ($i=0; $i<148; $i++)
  2422.             $v_checksum += ord(substr($v_binary_data_first,$i,1));
  2423.         // ..... Ignore the checksum value and replace it by ' ' (space)
  2424.         for ($i=148; $i<156; $i++)
  2425.             $v_checksum += ord(' ');
  2426.         // ..... Last part of the header
  2427.         for ($i=156, $j=0; $i<512; $i++, $j++)
  2428.             $v_checksum += ord(substr($v_binary_data_last,$j,1));
  2429.  
  2430.         // ----- Write the first 148 bytes of the header in the archive
  2431.         $this->_writeBlock($v_binary_data_first, 148);
  2432.  
  2433.         // ----- Write the calculated checksum
  2434.         $v_checksum = sprintf("%6s ", DecOct($v_checksum));
  2435.         $v_binary_data = pack("a8", $v_checksum);
  2436.         $this->_writeBlock($v_binary_data, 8);
  2437.  
  2438.         // ----- Write the last 356 bytes of the header in the archive
  2439.         $this->_writeBlock($v_binary_data_last, 356);
  2440.  
  2441.         // ----- Write the filename as content of the block
  2442.         $i=0;
  2443.         while (($v_buffer = substr($p_filename, (($i++)*512), 512)) != '') {
  2444.             $v_binary_data = pack("a512", "$v_buffer");
  2445.             $this->_writeBlock($v_binary_data);
  2446.         }
  2447.  
  2448.         return true;
  2449.     }
  2450.     // }}}
  2451.  
  2452.     // {{{ _readHeader()
  2453.     function _readHeader($v_binary_data, &$v_header)
  2454.     {
  2455.         if (strlen($v_binary_data)==0) {
  2456.             $v_header['filename'] = '';
  2457.             return true;
  2458.         }
  2459.  
  2460.         if (strlen($v_binary_data) != 512) {
  2461.             $v_header['filename'] = '';
  2462.             $this->_error('Invalid block size : '.strlen($v_binary_data));
  2463.             return false;
  2464.         }
  2465.  
  2466.         if (!is_array($v_header)) {
  2467.             $v_header = array();
  2468.         }
  2469.         // ----- Calculate the checksum
  2470.         $v_checksum = 0;
  2471.         // ..... First part of the header
  2472.         for ($i=0; $i<148; $i++)
  2473.             $v_checksum+=ord(substr($v_binary_data,$i,1));
  2474.         // ..... Ignore the checksum value and replace it by ' ' (space)
  2475.         for ($i=148; $i<156; $i++)
  2476.             $v_checksum += ord(' ');
  2477.         // ..... Last part of the header
  2478.         for ($i=156; $i<512; $i++)
  2479.            $v_checksum+=ord(substr($v_binary_data,$i,1));
  2480.  
  2481.         $v_data = unpack("a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/"
  2482.                          ."a8checksum/a1typeflag/a100link/a6magic/a2version/"
  2483.                          ."a32uname/a32gname/a8devmajor/a8devminor",
  2484.                          $v_binary_data);
  2485.  
  2486.         // ----- Extract the checksum
  2487.         $v_header['checksum'] = OctDec(trim($v_data['checksum']));
  2488.         if ($v_header['checksum'] != $v_checksum) {
  2489.             $v_header['filename'] = '';
  2490.  
  2491.             // ----- Look for last block (empty block)
  2492.             if (($v_checksum == 256) && ($v_header['checksum'] == 0))
  2493.                 return true;
  2494.  
  2495.             $this->_error('Invalid checksum for file "'.$v_data['filename']
  2496.                           .'" : '.$v_checksum.' calculated, '
  2497.                           .$v_header['checksum'].' expected');
  2498.             return false;
  2499.         }
  2500.  
  2501.         // ----- Extract the properties
  2502.         $v_header['filename'] = trim($v_data['filename']);
  2503.         if ($this->_maliciousFilename($v_header['filename'])) {
  2504.             $this->_error('Malicious .tar detected, file "' . $v_header['filename'] .
  2505.                 '" will not install in desired directory tree');
  2506.             return false;
  2507.         }
  2508.         $v_header['mode'] = OctDec(trim($v_data['mode']));
  2509.         $v_header['uid'] = OctDec(trim($v_data['uid']));
  2510.         $v_header['gid'] = OctDec(trim($v_data['gid']));
  2511.         $v_header['size'] = OctDec(trim($v_data['size']));
  2512.         $v_header['mtime'] = OctDec(trim($v_data['mtime']));
  2513.         if (($v_header['typeflag'] = $v_data['typeflag']) == "5") {
  2514.           $v_header['size'] = 0;
  2515.         }
  2516.         $v_header['link'] = trim($v_data['link']);
  2517.         /* ----- All these fields are removed form the header because
  2518.         they do not carry interesting info
  2519.         $v_header[magic] = trim($v_data[magic]);
  2520.         $v_header[version] = trim($v_data[version]);
  2521.         $v_header[uname] = trim($v_data[uname]);
  2522.         $v_header[gname] = trim($v_data[gname]);
  2523.         $v_header[devmajor] = trim($v_data[devmajor]);
  2524.         $v_header[devminor] = trim($v_data[devminor]);
  2525.         */
  2526.  
  2527.         return true;
  2528.     }
  2529.     // }}}
  2530.  
  2531.     // {{{ _maliciousFilename()
  2532.     /**
  2533.      * Detect and report a malicious file name
  2534.      *
  2535.      * @param string $file
  2536.      * @return bool
  2537.      * @access private
  2538.      */
  2539.     function _maliciousFilename($file)
  2540.     {
  2541.         if (strpos($file, '/../') !== false) {
  2542.             return true;
  2543.         }
  2544.         if (strpos($file, '../') === 0) {
  2545.             return true;
  2546.         }
  2547.         return false;
  2548.     }
  2549.     // }}}
  2550.  
  2551.     // {{{ _readLongHeader()
  2552.     function _readLongHeader(&$v_header)
  2553.     {
  2554.       $v_filename = '';
  2555.       $n = floor($v_header['size']/512);
  2556.       for ($i=0; $i<$n; $i++) {
  2557.         $v_content = $this->_readBlock();
  2558.         $v_filename .= $v_content;
  2559.       }
  2560.       if (($v_header['size'] % 512) != 0) {
  2561.         $v_content = $this->_readBlock();
  2562.         $v_filename .= $v_content;
  2563.       }
  2564.  
  2565.       // ----- Read the next header
  2566.       $v_binary_data = $this->_readBlock();
  2567.  
  2568.       if (!$this->_readHeader($v_binary_data, $v_header))
  2569.         return false;
  2570.  
  2571.       $v_header['filename'] = $v_filename;
  2572.         if ($this->_maliciousFilename($v_filename)) {
  2573.             $this->_error('Malicious .tar detected, file "' . $v_filename .
  2574.                 '" will not install in desired directory tree');
  2575.             return false;
  2576.       }
  2577.  
  2578.       return true;
  2579.     }
  2580.     // }}}
  2581.  
  2582.     // {{{ _extractInString()
  2583.     /**
  2584.     * This method extract from the archive one file identified by $p_filename.
  2585.     * The return value is a string with the file content, or NULL on error.
  2586.     * @param string $p_filename     The path of the file to extract in a string.
  2587.     * @return                       a string with the file content or NULL.
  2588.     * @access private
  2589.     */
  2590.     function _extractInString($p_filename)
  2591.     {
  2592.         $v_result_str = "";
  2593.  
  2594.         While (strlen($v_binary_data = $this->_readBlock()) != 0)
  2595.         {
  2596.           if (!$this->_readHeader($v_binary_data, $v_header))
  2597.             return NULL;
  2598.  
  2599.           if ($v_header['filename'] == '')
  2600.             continue;
  2601.  
  2602.           // ----- Look for long filename
  2603.           if ($v_header['typeflag'] == 'L') {
  2604.             if (!$this->_readLongHeader($v_header))
  2605.               return NULL;
  2606.           }
  2607.  
  2608.           if ($v_header['filename'] == $p_filename) {
  2609.               if ($v_header['typeflag'] == "5") {
  2610.                   $this->_error('Unable to extract in string a directory '
  2611.                                 .'entry {'.$v_header['filename'].'}');
  2612.                   return NULL;
  2613.               } else {
  2614.                   $n = floor($v_header['size']/512);
  2615.                   for ($i=0; $i<$n; $i++) {
  2616.                       $v_result_str .= $this->_readBlock();
  2617.                   }
  2618.                   if (($v_header['size'] % 512) != 0) {
  2619.                       $v_content = $this->_readBlock();
  2620.                       $v_result_str .= substr($v_content, 0,
  2621.                                               ($v_header['size'] % 512));
  2622.                   }
  2623.                   return $v_result_str;
  2624.               }
  2625.           } else {
  2626.               $this->_jumpBlock(ceil(($v_header['size']/512)));
  2627.           }
  2628.         }
  2629.  
  2630.         return NULL;
  2631.     }
  2632.     // }}}
  2633.  
  2634.     // {{{ _extractList()
  2635.     function _extractList($p_path, &$p_list_detail, $p_mode,
  2636.                           $p_file_list, $p_remove_path)
  2637.     {
  2638.     $v_result=true;
  2639.     $v_nb = 0;
  2640.     $v_extract_all = true;
  2641.     $v_listing = false;
  2642.  
  2643.     $p_path = $this->_translateWinPath($p_path, false);
  2644.     if ($p_path == '' || (substr($p_path, 0, 1) != '/'
  2645.         && substr($p_path, 0, 3) != "../" && !strpos($p_path, ':'))) {
  2646.       $p_path = "./".$p_path;
  2647.     }
  2648.     $p_remove_path = $this->_translateWinPath($p_remove_path);
  2649.  
  2650.     // ----- Look for path to remove format (should end by /)
  2651.     if (($p_remove_path != '') && (substr($p_remove_path, -1) != '/'))
  2652.       $p_remove_path .= '/';
  2653.     $p_remove_path_size = strlen($p_remove_path);
  2654.  
  2655.     switch ($p_mode) {
  2656.       case "complete" :
  2657.         $v_extract_all = TRUE;
  2658.         $v_listing = FALSE;
  2659.       break;
  2660.       case "partial" :
  2661.           $v_extract_all = FALSE;
  2662.           $v_listing = FALSE;
  2663.       break;
  2664.       case "list" :
  2665.           $v_extract_all = FALSE;
  2666.           $v_listing = TRUE;
  2667.       break;
  2668.       default :
  2669.         $this->_error('Invalid extract mode ('.$p_mode.')');
  2670.         return false;
  2671.     }
  2672.  
  2673.     clearstatcache();
  2674.  
  2675.     while (strlen($v_binary_data = $this->_readBlock()) != 0)
  2676.     {
  2677.       $v_extract_file = FALSE;
  2678.       $v_extraction_stopped = 0;
  2679.  
  2680.       if (!$this->_readHeader($v_binary_data, $v_header))
  2681.         return false;
  2682.  
  2683.       if ($v_header['filename'] == '') {
  2684.         continue;
  2685.       }
  2686.  
  2687.       // ----- Look for long filename
  2688.       if ($v_header['typeflag'] == 'L') {
  2689.         if (!$this->_readLongHeader($v_header))
  2690.           return false;
  2691.       }
  2692.  
  2693.       if ((!$v_extract_all) && (is_array($p_file_list))) {
  2694.         // ----- By default no unzip if the file is not found
  2695.         $v_extract_file = false;
  2696.  
  2697.         for ($i=0; $i<sizeof($p_file_list); $i++) {
  2698.           // ----- Look if it is a directory
  2699.           if (substr($p_file_list[$i], -1) == '/') {
  2700.             // ----- Look if the directory is in the filename path
  2701.             if ((strlen($v_header['filename']) > strlen($p_file_list[$i]))
  2702.                 && (substr($v_header['filename'], 0, strlen($p_file_list[$i]))
  2703.                     == $p_file_list[$i])) {
  2704.               $v_extract_file = TRUE;
  2705.               break;
  2706.             }
  2707.           }
  2708.  
  2709.           // ----- It is a file, so compare the file names
  2710.           elseif ($p_file_list[$i] == $v_header['filename']) {
  2711.             $v_extract_file = TRUE;
  2712.             break;
  2713.           }
  2714.         }
  2715.       } else {
  2716.         $v_extract_file = TRUE;
  2717.       }
  2718.  
  2719.       // ----- Look if this file need to be extracted
  2720.       if (($v_extract_file) && (!$v_listing))
  2721.       {
  2722.         if (($p_remove_path != '')
  2723.             && (substr($v_header['filename'], 0, $p_remove_path_size)
  2724.                 == $p_remove_path))
  2725.           $v_header['filename'] = substr($v_header['filename'],
  2726.                                          $p_remove_path_size);
  2727.         if (($p_path != './') && ($p_path != '/')) {
  2728.           while (substr($p_path, -1) == '/')
  2729.             $p_path = substr($p_path, 0, strlen($p_path)-1);
  2730.  
  2731.           if (substr($v_header['filename'], 0, 1) == '/')
  2732.               $v_header['filename'] = $p_path.$v_header['filename'];
  2733.           else
  2734.             $v_header['filename'] = $p_path.'/'.$v_header['filename'];
  2735.         }
  2736.         if (file_exists($v_header['filename'])) {
  2737.           if (   (@is_dir($v_header['filename']))
  2738.               && ($v_header['typeflag'] == '')) {
  2739.             $this->_error('File '.$v_header['filename']
  2740.                           .' already exists as a directory');
  2741.             return false;
  2742.           }
  2743.           if (   ($this->_isArchive($v_header['filename']))
  2744.               && ($v_header['typeflag'] == "5")) {
  2745.             $this->_error('Directory '.$v_header['filename']
  2746.                           .' already exists as a file');
  2747.             return false;
  2748.           }
  2749.           if (!is_writeable($v_header['filename'])) {
  2750.             $this->_error('File '.$v_header['filename']
  2751.                           .' already exists and is write protected');
  2752.             return false;
  2753.           }
  2754.           if (filemtime($v_header['filename']) > $v_header['mtime']) {
  2755.             // To be completed : An error or silent no replace ?
  2756.           }
  2757.         }
  2758.  
  2759.         // ----- Check the directory availability and create it if necessary
  2760.         elseif (($v_result
  2761.                  = $this->_dirCheck(($v_header['typeflag'] == "5"
  2762.                                     ?$v_header['filename']
  2763.                                     :dirname($v_header['filename'])))) != 1) {
  2764.             $this->_error('Unable to create path for '.$v_header['filename']);
  2765.             return false;
  2766.         }
  2767.  
  2768.         if ($v_extract_file) {
  2769.           if ($v_header['typeflag'] == "5") {
  2770.             if (!@file_exists($v_header['filename'])) {
  2771.                 if (!@mkdir($v_header['filename'], 0777)) {
  2772.                     $this->_error('Unable to create directory {'
  2773.                                   .$v_header['filename'].'}');
  2774.                     return false;
  2775.                 }
  2776.             }
  2777.           } elseif ($v_header['typeflag'] == "2") {
  2778.               if (!@symlink($v_header['link'], $v_header['filename'])) {
  2779.                   $this->_error('Unable to extract symbolic link {'
  2780.                                 .$v_header['filename'].'}');
  2781.                   return false;
  2782.               }
  2783.           } else {
  2784.               if (($v_dest_file = @fopen($v_header['filename'], "wb")) == 0) {
  2785.                   $this->_error('Error while opening {'.$v_header['filename']
  2786.                                 .'} in write binary mode');
  2787.                   return false;
  2788.               } else {
  2789.                   $n = floor($v_header['size']/512);
  2790.                   for ($i=0; $i<$n; $i++) {
  2791.                       $v_content = $this->_readBlock();
  2792.                       fwrite($v_dest_file, $v_content, 512);
  2793.                   }
  2794.             if (($v_header['size'] % 512) != 0) {
  2795.               $v_content = $this->_readBlock();
  2796.               fwrite($v_dest_file, $v_content, ($v_header['size'] % 512));
  2797.             }
  2798.  
  2799.             @fclose($v_dest_file);
  2800.  
  2801.             // ----- Change the file mode, mtime
  2802.             @touch($v_header['filename'], $v_header['mtime']);
  2803.             if ($v_header['mode'] & 0111) {
  2804.                 // make file executable, obey umask
  2805.                 $mode = fileperms($v_header['filename']) | (~umask() & 0111);
  2806.                 @chmod($v_header['filename'], $mode);
  2807.             }
  2808.           }
  2809.  
  2810.           // ----- Check the file size
  2811.           clearstatcache();
  2812.           if (filesize($v_header['filename']) != $v_header['size']) {
  2813.               $this->_error('Extracted file '.$v_header['filename']
  2814.                             .' does not have the correct file size \''
  2815.                             .filesize($v_header['filename'])
  2816.                             .'\' ('.$v_header['size']
  2817.                             .' expected). Archive may be corrupted.');
  2818.               return false;
  2819.           }
  2820.           }
  2821.         } else {
  2822.           $this->_jumpBlock(ceil(($v_header['size']/512)));
  2823.         }
  2824.       } else {
  2825.           $this->_jumpBlock(ceil(($v_header['size']/512)));
  2826.       }
  2827.  
  2828.       /* TBC : Seems to be unused ...
  2829.       if ($this->_compress)
  2830.         $v_end_of_file = @gzeof($this->_file);
  2831.       else
  2832.         $v_end_of_file = @feof($this->_file);
  2833.         */
  2834.  
  2835.       if ($v_listing || $v_extract_file || $v_extraction_stopped) {
  2836.         // ----- Log extracted files
  2837.         if (($v_file_dir = dirname($v_header['filename']))
  2838.             == $v_header['filename'])
  2839.           $v_file_dir = '';
  2840.         if ((substr($v_header['filename'], 0, 1) == '/') && ($v_file_dir == ''))
  2841.           $v_file_dir = '/';
  2842.  
  2843.         $p_list_detail[$v_nb++] = $v_header;
  2844.         if (is_array($p_file_list) && (count($p_list_detail) == count($p_file_list))) {
  2845.             return true;
  2846.         }
  2847.       }
  2848.     }
  2849.  
  2850.         return true;
  2851.     }
  2852.     // }}}
  2853.  
  2854.     // {{{ _openAppend()
  2855.     function _openAppend()
  2856.     {
  2857.         if (filesize($this->_tarname) == 0)
  2858.           return $this->_openWrite();
  2859.           
  2860.         if ($this->_compress) {
  2861.             $this->_close();
  2862.  
  2863.             if (!@rename($this->_tarname, $this->_tarname.".tmp")) {
  2864.                 $this->_error('Error while renaming \''.$this->_tarname
  2865.                               .'\' to temporary file \''.$this->_tarname
  2866.                               .'.tmp\'');
  2867.                 return false;
  2868.             }
  2869.  
  2870.             if ($this->_compress_type == 'gz')
  2871.                 $v_temp_tar = @gzopen($this->_tarname.".tmp", "rb");
  2872.             elseif ($this->_compress_type == 'bz2')
  2873.                 $v_temp_tar = @bzopen($this->_tarname.".tmp", "rb");
  2874.                 
  2875.             if ($v_temp_tar == 0) {
  2876.                 $this->_error('Unable to open file \''.$this->_tarname
  2877.                               .'.tmp\' in binary read mode');
  2878.                 @rename($this->_tarname.".tmp", $this->_tarname);
  2879.                 return false;
  2880.             }
  2881.  
  2882.             if (!$this->_openWrite()) {
  2883.                 @rename($this->_tarname.".tmp", $this->_tarname);
  2884.                 return false;
  2885.             }
  2886.  
  2887.             if ($this->_compress_type == 'gz') {
  2888.                 while (!@gzeof($v_temp_tar)) {
  2889.                     $v_buffer = @gzread($v_temp_tar, 512);
  2890.                     if ($v_buffer == ARCHIVE_TAR_END_BLOCK) {
  2891.                         // do not copy end blocks, we will re-make them
  2892.                         // after appending
  2893.                         continue;
  2894.                     }
  2895.                     $v_binary_data = pack("a512", $v_buffer);
  2896.                     $this->_writeBlock($v_binary_data);
  2897.                 }
  2898.  
  2899.                 @gzclose($v_temp_tar);
  2900.             }
  2901.             elseif ($this->_compress_type == 'bz2') {
  2902.                 while (strlen($v_buffer = @bzread($v_temp_tar, 512)) > 0) {
  2903.                     if ($v_buffer == ARCHIVE_TAR_END_BLOCK) {
  2904.                         continue;
  2905.                     }
  2906.                     $v_binary_data = pack("a512", $v_buffer);
  2907.                     $this->_writeBlock($v_binary_data);
  2908.                 }
  2909.  
  2910.                 @bzclose($v_temp_tar);
  2911.             }
  2912.  
  2913.             if (!@unlink($this->_tarname.".tmp")) {
  2914.                 $this->_error('Error while deleting temporary file \''
  2915.                               .$this->_tarname.'.tmp\'');
  2916.             }
  2917.  
  2918.         } else {
  2919.             // ----- For not compressed tar, just add files before the last
  2920.             //       one or two 512 bytes block
  2921.             if (!$this->_openReadWrite())
  2922.                return false;
  2923.  
  2924.             clearstatcache();
  2925.             $v_size = filesize($this->_tarname);
  2926.  
  2927.             // We might have zero, one or two end blocks.
  2928.             // The standard is two, but we should try to handle 
  2929.             // other cases.
  2930.             fseek($this->_file, $v_size - 1024);
  2931.             if (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) {
  2932.                 fseek($this->_file, $v_size - 1024);
  2933.             }
  2934.             elseif (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) {
  2935.                 fseek($this->_file, $v_size - 512);    
  2936.             }
  2937.         }
  2938.  
  2939.         return true;
  2940.     }
  2941.     // }}}
  2942.  
  2943.     // {{{ _append()
  2944.     function _append($p_filelist, $p_add_dir='', $p_remove_dir='')
  2945.     {
  2946.         if (!$this->_openAppend())
  2947.             return false;
  2948.             
  2949.         if ($this->_addList($p_filelist, $p_add_dir, $p_remove_dir))
  2950.            $this->_writeFooter();
  2951.  
  2952.         $this->_close();
  2953.  
  2954.         return true;
  2955.     }
  2956.     // }}}
  2957.  
  2958.     // {{{ _dirCheck()
  2959.  
  2960.     /**
  2961.      * Check if a directory exists and create it (including parent
  2962.      * dirs) if not.
  2963.      *
  2964.      * @param string $p_dir directory to check
  2965.      *
  2966.      * @return bool TRUE if the directory exists or was created
  2967.      */
  2968.     function _dirCheck($p_dir)
  2969.     {
  2970.         clearstatcache();
  2971.         if ((@is_dir($p_dir)) || ($p_dir == ''))
  2972.             return true;
  2973.  
  2974.         $p_parent_dir = dirname($p_dir);
  2975.  
  2976.         if (($p_parent_dir != $p_dir) &&
  2977.             ($p_parent_dir != '') &&
  2978.             (!$this->_dirCheck($p_parent_dir)))
  2979.              return false;
  2980.  
  2981.         if (!@mkdir($p_dir, 0777)) {
  2982.             $this->_error("Unable to create directory '$p_dir'");
  2983.             return false;
  2984.         }
  2985.  
  2986.         return true;
  2987.     }
  2988.  
  2989.     // }}}
  2990.  
  2991.     // {{{ _pathReduction()
  2992.  
  2993.     /**
  2994.      * Compress path by changing for example "/dir/foo/../bar" to "/dir/bar", 
  2995.      * rand emove double slashes.
  2996.      *
  2997.      * @param string $p_dir path to reduce
  2998.      *
  2999.      * @return string reduced path
  3000.      *
  3001.      * @access private
  3002.      *
  3003.      */
  3004.     function _pathReduction($p_dir)
  3005.     {
  3006.         $v_result = '';
  3007.  
  3008.         // ----- Look for not empty path
  3009.         if ($p_dir != '') {
  3010.             // ----- Explode path by directory names
  3011.             $v_list = explode('/', $p_dir);
  3012.  
  3013.             // ----- Study directories from last to first
  3014.             for ($i=sizeof($v_list)-1; $i>=0; $i--) {
  3015.                 // ----- Look for current path
  3016.                 if ($v_list[$i] == ".") {
  3017.                     // ----- Ignore this directory
  3018.                     // Should be the first $i=0, but no check is done
  3019.                 }
  3020.                 else if ($v_list[$i] == "..") {
  3021.                     // ----- Ignore it and ignore the $i-1
  3022.                     $i--;
  3023.                 }
  3024.                 else if (   ($v_list[$i] == '')
  3025.                          && ($i!=(sizeof($v_list)-1))
  3026.                          && ($i!=0)) {
  3027.                     // ----- Ignore only the double '//' in path,
  3028.                     // but not the first and last /
  3029.                 } else {
  3030.                     $v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?'/'
  3031.                                 .$v_result:'');
  3032.                 }
  3033.             }
  3034.         }
  3035.         $v_result = strtr($v_result, '\\', '/');
  3036.         return $v_result;
  3037.     }
  3038.  
  3039.     // }}}
  3040.  
  3041.     // {{{ _translateWinPath()
  3042.     function _translateWinPath($p_path, $p_remove_disk_letter=true)
  3043.     {
  3044.       if (defined('OS_WINDOWS') && OS_WINDOWS) {
  3045.           // ----- Look for potential disk letter
  3046.           if (   ($p_remove_disk_letter)
  3047.               && (($v_position = strpos($p_path, ':')) != false)) {
  3048.               $p_path = substr($p_path, $v_position+1);
  3049.           }
  3050.           // ----- Change potential windows directory separator
  3051.           if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0,1) == '\\')) {
  3052.               $p_path = strtr($p_path, '\\', '/');
  3053.           }
  3054.       }
  3055.       return $p_path;
  3056.     }
  3057.     // }}}
  3058.  
  3059. }
  3060. ?>
  3061. <?php
  3062. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3063. // +----------------------------------------------------------------------+
  3064. // | PHP Version 5                                                        |
  3065. // +----------------------------------------------------------------------+
  3066. // | Copyright (c) 1997-2004 The PHP Group                                |
  3067. // +----------------------------------------------------------------------+
  3068. // | This source file is subject to version 3.0 of the PHP license,       |
  3069. // | that is bundled with this package in the file LICENSE, and is        |
  3070. // | available through the world-wide-web at the following url:           |
  3071. // | http://www.php.net/license/3_0.txt.                                  |
  3072. // | If you did not receive a copy of the PHP license and are unable to   |
  3073. // | obtain it through the world-wide-web, please send a note to          |
  3074. // | license@php.net so we can mail you a copy immediately.               |
  3075. // +----------------------------------------------------------------------+
  3076. // | Author: Andrei Zmievski <andrei@php.net>                             |
  3077. // +----------------------------------------------------------------------+
  3078. //
  3079. // $Id: Getopt.php,v 1.32 2007/02/18 04:13:07 cellog Exp $
  3080.  
  3081. require_once 'phar://go-pear.phar/' . 'PEAR.php';
  3082.  
  3083. /**
  3084.  * Command-line options parsing class.
  3085.  *
  3086.  * @author Andrei Zmievski <andrei@php.net>
  3087.  *
  3088.  */
  3089. class Console_Getopt {
  3090.     /**
  3091.      * Parses the command-line options.
  3092.      *
  3093.      * The first parameter to this function should be the list of command-line
  3094.      * arguments without the leading reference to the running program.
  3095.      *
  3096.      * The second parameter is a string of allowed short options. Each of the
  3097.      * option letters can be followed by a colon ':' to specify that the option
  3098.      * requires an argument, or a double colon '::' to specify that the option
  3099.      * takes an optional argument.
  3100.      *
  3101.      * The third argument is an optional array of allowed long options. The
  3102.      * leading '--' should not be included in the option name. Options that
  3103.      * require an argument should be followed by '=', and options that take an
  3104.      * option argument should be followed by '=='.
  3105.      *
  3106.      * The return value is an array of two elements: the list of parsed
  3107.      * options and the list of non-option command-line arguments. Each entry in
  3108.      * the list of parsed options is a pair of elements - the first one
  3109.      * specifies the option, and the second one specifies the option argument,
  3110.      * if there was one.
  3111.      *
  3112.      * Long and short options can be mixed.
  3113.      *
  3114.      * Most of the semantics of this function are based on GNU getopt_long().
  3115.      *
  3116.      * @param array  $args           an array of command-line arguments
  3117.      * @param string $short_options  specifies the list of allowed short options
  3118.      * @param array  $long_options   specifies the list of allowed long options
  3119.      *
  3120.      * @return array two-element array containing the list of parsed options and
  3121.      * the non-option arguments
  3122.      *
  3123.      * @access public
  3124.      *
  3125.      */
  3126.     function getopt2($args, $short_options, $long_options = null)
  3127.     {
  3128.         return Console_Getopt::doGetopt(2, $args, $short_options, $long_options);
  3129.     }
  3130.  
  3131.     /**
  3132.      * This function expects $args to start with the script name (POSIX-style).
  3133.      * Preserved for backwards compatibility.
  3134.      * @see getopt2()
  3135.      */    
  3136.     function getopt($args, $short_options, $long_options = null)
  3137.     {
  3138.         return Console_Getopt::doGetopt(1, $args, $short_options, $long_options);
  3139.     }
  3140.  
  3141.     /**
  3142.      * The actual implementation of the argument parsing code.
  3143.      */
  3144.     function doGetopt($version, $args, $short_options, $long_options = null)
  3145.     {
  3146.         // in case you pass directly readPHPArgv() as the first arg
  3147.         if (PEAR::isError($args)) {
  3148.             return $args;
  3149.         }
  3150.         if (empty($args)) {
  3151.             return array(array(), array());
  3152.         }
  3153.         $opts     = array();
  3154.         $non_opts = array();
  3155.  
  3156.         settype($args, 'array');
  3157.  
  3158.         if ($long_options) {
  3159.             sort($long_options);
  3160.         }
  3161.  
  3162.         /*
  3163.          * Preserve backwards compatibility with callers that relied on
  3164.          * erroneous POSIX fix.
  3165.          */
  3166.         if ($version < 2) {
  3167.             if (isset($args[0]{0}) && $args[0]{0} != '-') {
  3168.                 array_shift($args);
  3169.             }
  3170.         }
  3171.  
  3172.         reset($args);
  3173.         while (list($i, $arg) = each($args)) {
  3174.  
  3175.             /* The special element '--' means explicit end of
  3176.                options. Treat the rest of the arguments as non-options
  3177.                and end the loop. */
  3178.             if ($arg == '--') {
  3179.                 $non_opts = array_merge($non_opts, array_slice($args, $i + 1));
  3180.                 break;
  3181.             }
  3182.  
  3183.             if ($arg{0} != '-' || (strlen($arg) > 1 && $arg{1} == '-' && !$long_options)) {
  3184.                 $non_opts = array_merge($non_opts, array_slice($args, $i));
  3185.                 break;
  3186.             } elseif (strlen($arg) > 1 && $arg{1} == '-') {
  3187.                 $error = Console_Getopt::_parseLongOption(substr($arg, 2), $long_options, $opts, $args);
  3188.                 if (PEAR::isError($error))
  3189.                     return $error;
  3190.             } else {
  3191.                 $error = Console_Getopt::_parseShortOption(substr($arg, 1), $short_options, $opts, $args);
  3192.                 if (PEAR::isError($error))
  3193.                     return $error;
  3194.             }
  3195.         }
  3196.  
  3197.         return array($opts, $non_opts);
  3198.     }
  3199.  
  3200.     /**
  3201.      * @access private
  3202.      *
  3203.      */
  3204.     function _parseShortOption($arg, $short_options, &$opts, &$args)
  3205.     {
  3206.         for ($i = 0; $i < strlen($arg); $i++) {
  3207.             $opt = $arg{$i};
  3208.             $opt_arg = null;
  3209.  
  3210.             /* Try to find the short option in the specifier string. */
  3211.             if (($spec = strstr($short_options, $opt)) === false || $arg{$i} == ':')
  3212.             {
  3213.                 return PEAR::raiseError("Console_Getopt: unrecognized option -- $opt");
  3214.             }
  3215.  
  3216.             if (strlen($spec) > 1 && $spec{1} == ':') {
  3217.                 if (strlen($spec) > 2 && $spec{2} == ':') {
  3218.                     if ($i + 1 < strlen($arg)) {
  3219.                         /* Option takes an optional argument. Use the remainder of
  3220.                            the arg string if there is anything left. */
  3221.                         $opts[] = array($opt, substr($arg, $i + 1));
  3222.                         break;
  3223.                     }
  3224.                 } else {
  3225.                     /* Option requires an argument. Use the remainder of the arg
  3226.                        string if there is anything left. */
  3227.                     if ($i + 1 < strlen($arg)) {
  3228.                         $opts[] = array($opt,  substr($arg, $i + 1));
  3229.                         break;
  3230.                     } else if (list(, $opt_arg) = each($args)) {
  3231.                         /* Else use the next argument. */;
  3232.                         if (Console_Getopt::_isShortOpt($opt_arg) || Console_Getopt::_isLongOpt($opt_arg)) {
  3233.                             return PEAR::raiseError("Console_Getopt: option requires an argument -- $opt");
  3234.                         }
  3235.                     } else {
  3236.                         return PEAR::raiseError("Console_Getopt: option requires an argument -- $opt");
  3237.                     }
  3238.                 }
  3239.             }
  3240.  
  3241.             $opts[] = array($opt, $opt_arg);
  3242.         }
  3243.     }
  3244.  
  3245.     /**
  3246.      * @access private
  3247.      *
  3248.      */
  3249.     function _isShortOpt($arg)
  3250.     {
  3251.         return strlen($arg) == 2 && $arg[0] == '-' && preg_match('/[a-zA-Z]/', $arg[1]);
  3252.     }
  3253.  
  3254.     /**
  3255.      * @access private
  3256.      *
  3257.      */
  3258.     function _isLongOpt($arg)
  3259.     {
  3260.         return strlen($arg) > 2 && $arg[0] == '-' && $arg[1] == '-' &&
  3261.             preg_match('/[a-zA-Z]+$/', substr($arg, 2));
  3262.     }
  3263.  
  3264.     /**
  3265.      * @access private
  3266.      *
  3267.      */
  3268.     function _parseLongOption($arg, $long_options, &$opts, &$args)
  3269.     {
  3270.         @list($opt, $opt_arg) = explode('=', $arg, 2);
  3271.         $opt_len = strlen($opt);
  3272.  
  3273.         for ($i = 0; $i < count($long_options); $i++) {
  3274.             $long_opt  = $long_options[$i];
  3275.             $opt_start = substr($long_opt, 0, $opt_len);
  3276.             $long_opt_name = str_replace('=', '', $long_opt);
  3277.  
  3278.             /* Option doesn't match. Go on to the next one. */
  3279.             if ($long_opt_name != $opt) {
  3280.                 continue;
  3281.             }
  3282.  
  3283.             $opt_rest  = substr($long_opt, $opt_len);
  3284.  
  3285.             /* Check that the options uniquely matches one of the allowed
  3286.                options. */
  3287.             $next_option_rest = substr($long_options[$i + 1], $opt_len);
  3288.             if ($opt_rest != '' && $opt{0} != '=' &&
  3289.                 $i + 1 < count($long_options) &&
  3290.                 $opt == substr($long_options[$i+1], 0, $opt_len) &&
  3291.                 $next_option_rest != '' &&
  3292.                 $next_option_rest{0} != '=') {
  3293.                 return PEAR::raiseError("Console_Getopt: option --$opt is ambiguous");
  3294.             }
  3295.  
  3296.             if (substr($long_opt, -1) == '=') {
  3297.                 if (substr($long_opt, -2) != '==') {
  3298.                     /* Long option requires an argument.
  3299.                        Take the next argument if one wasn't specified. */;
  3300.                     if (!strlen($opt_arg) && !(list(, $opt_arg) = each($args))) {
  3301.                         return PEAR::raiseError("Console_Getopt: option --$opt requires an argument");
  3302.                     }
  3303.                 }
  3304.             } else if ($opt_arg) {
  3305.                 return PEAR::raiseError("Console_Getopt: option --$opt doesn't allow an argument");
  3306.             }
  3307.  
  3308.             $opts[] = array('--' . $opt, $opt_arg);
  3309.             return;
  3310.         }
  3311.  
  3312.         return PEAR::raiseError("Console_Getopt: unrecognized option --$opt");
  3313.     }
  3314.  
  3315.     /**
  3316.     * Safely read the $argv PHP array across different PHP configurations.
  3317.     * Will take care on register_globals and register_argc_argv ini directives
  3318.     *
  3319.     * @access public
  3320.     * @return mixed the $argv PHP array or PEAR error if not registered
  3321.     */
  3322.     function readPHPArgv()
  3323.     {
  3324.         global $argv;
  3325.         if (!is_array($argv)) {
  3326.             if (!@is_array($_SERVER['argv'])) {
  3327.                 if (!@is_array($GLOBALS['HTTP_SERVER_VARS']['argv'])) {
  3328.                     return PEAR::raiseError("Console_Getopt: Could not read cmd args (register_argc_argv=Off?)");
  3329.                 }
  3330.                 return $GLOBALS['HTTP_SERVER_VARS']['argv'];
  3331.             }
  3332.             return $_SERVER['argv'];
  3333.         }
  3334.         return $argv;
  3335.     }
  3336.  
  3337. }
  3338.  
  3339. ?>
  3340. <?php
  3341. require_once 'phar://go-pear.phar/PEAR/Start/CLI.php';
  3342. PEAR::setErrorHandling(PEAR_ERROR_DIE);
  3343. $a = new PEAR_Start_CLI;
  3344. $a->run();
  3345. ?><?php
  3346. /**
  3347.  * The OS_Guess class
  3348.  *
  3349.  * PHP versions 4 and 5
  3350.  *
  3351.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  3352.  * that is available through the world-wide-web at the following URI:
  3353.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  3354.  * the PHP License and are unable to obtain it through the web, please
  3355.  * send a note to license@php.net so we can mail you a copy immediately.
  3356.  *
  3357.  * @category   pear
  3358.  * @package    PEAR
  3359.  * @author     Stig Bakken <ssb@php.net>
  3360.  * @author     Gregory Beaver <cellog@php.net>
  3361.  * @copyright  1997-2008 The PHP Group
  3362.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  3363.  * @version    CVS: $Id: Guess.php,v 1.26 2008/01/03 20:26:34 cellog Exp $
  3364.  * @link       http://pear.php.net/package/PEAR
  3365.  * @since      File available since PEAR 0.1
  3366.  */
  3367.  
  3368. // {{{ uname examples
  3369.  
  3370. // php_uname() without args returns the same as 'uname -a', or a PHP-custom
  3371. // string for Windows.
  3372. // PHP versions prior to 4.3 return the uname of the host where PHP was built,
  3373. // as of 4.3 it returns the uname of the host running the PHP code.
  3374. //
  3375. // PC RedHat Linux 7.1:
  3376. // Linux host.example.com 2.4.2-2 #1 Sun Apr 8 20:41:30 EDT 2001 i686 unknown
  3377. //
  3378. // PC Debian Potato:
  3379. // Linux host 2.4.17 #2 SMP Tue Feb 12 15:10:04 CET 2002 i686 unknown
  3380. //
  3381. // PC FreeBSD 3.3:
  3382. // FreeBSD host.example.com 3.3-STABLE FreeBSD 3.3-STABLE #0: Mon Feb 21 00:42:31 CET 2000     root@example.com:/usr/src/sys/compile/CONFIG  i386
  3383. //
  3384. // PC FreeBSD 4.3:
  3385. // FreeBSD host.example.com 4.3-RELEASE FreeBSD 4.3-RELEASE #1: Mon Jun 25 11:19:43 EDT 2001     root@example.com:/usr/src/sys/compile/CONFIG  i386
  3386. //
  3387. // PC FreeBSD 4.5:
  3388. // FreeBSD host.example.com 4.5-STABLE FreeBSD 4.5-STABLE #0: Wed Feb  6 23:59:23 CET 2002     root@example.com:/usr/src/sys/compile/CONFIG  i386
  3389. //
  3390. // PC FreeBSD 4.5 w/uname from GNU shellutils:
  3391. // FreeBSD host.example.com 4.5-STABLE FreeBSD 4.5-STABLE #0: Wed Feb  i386 unknown
  3392. //
  3393. // HP 9000/712 HP-UX 10:
  3394. // HP-UX iq B.10.10 A 9000/712 2008429113 two-user license
  3395. //
  3396. // HP 9000/712 HP-UX 10 w/uname from GNU shellutils:
  3397. // HP-UX host B.10.10 A 9000/712 unknown
  3398. //
  3399. // IBM RS6000/550 AIX 4.3:
  3400. // AIX host 3 4 000003531C00
  3401. //
  3402. // AIX 4.3 w/uname from GNU shellutils:
  3403. // AIX host 3 4 000003531C00 unknown
  3404. //
  3405. // SGI Onyx IRIX 6.5 w/uname from GNU shellutils:
  3406. // IRIX64 host 6.5 01091820 IP19 mips
  3407. //
  3408. // SGI Onyx IRIX 6.5:
  3409. // IRIX64 host 6.5 01091820 IP19
  3410. //
  3411. // SparcStation 20 Solaris 8 w/uname from GNU shellutils:
  3412. // SunOS host.example.com 5.8 Generic_108528-12 sun4m sparc
  3413. //
  3414. // SparcStation 20 Solaris 8:
  3415. // SunOS host.example.com 5.8 Generic_108528-12 sun4m sparc SUNW,SPARCstation-20
  3416. //
  3417. // Mac OS X (Darwin)
  3418. // Darwin home-eden.local 7.5.0 Darwin Kernel Version 7.5.0: Thu Aug  5 19:26:16 PDT 2004; root:xnu/xnu-517.7.21.obj~3/RELEASE_PPC  Power Macintosh
  3419. //
  3420. // Mac OS X early versions
  3421. // 
  3422.  
  3423. // }}}
  3424.  
  3425. /* TODO:
  3426.  * - define endianness, to allow matchSignature("bigend") etc.
  3427.  */
  3428.  
  3429. /**
  3430.  * Retrieves information about the current operating system
  3431.  *
  3432.  * This class uses php_uname() to grok information about the current OS
  3433.  *
  3434.  * @category   pear
  3435.  * @package    PEAR
  3436.  * @author     Stig Bakken <ssb@php.net>
  3437.  * @author     Gregory Beaver <cellog@php.net>
  3438.  * @copyright  1997-2008 The PHP Group
  3439.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  3440.  * @version    Release: 1.7.1
  3441.  * @link       http://pear.php.net/package/PEAR
  3442.  * @since      Class available since Release 0.1
  3443.  */
  3444. class OS_Guess
  3445. {
  3446.     var $sysname;
  3447.     var $nodename;
  3448.     var $cpu;
  3449.     var $release;
  3450.     var $extra;
  3451.  
  3452.     function OS_Guess($uname = null)
  3453.     {
  3454.         list($this->sysname,
  3455.              $this->release,
  3456.              $this->cpu,
  3457.              $this->extra,
  3458.              $this->nodename) = $this->parseSignature($uname);
  3459.     }
  3460.  
  3461.     function parseSignature($uname = null)
  3462.     {
  3463.         static $sysmap = array(
  3464.             'HP-UX' => 'hpux',
  3465.             'IRIX64' => 'irix',
  3466.         );
  3467.         static $cpumap = array(
  3468.             'i586' => 'i386',
  3469.             'i686' => 'i386',
  3470.             'ppc' => 'powerpc',
  3471.         );
  3472.         if ($uname === null) {
  3473.             $uname = php_uname();
  3474.         }
  3475.         $parts = split('[[:space:]]+', trim($uname));
  3476.         $n = count($parts);
  3477.  
  3478.         $release = $machine = $cpu = '';
  3479.         $sysname = $parts[0];
  3480.         $nodename = $parts[1];
  3481.         $cpu = $parts[$n-1];
  3482.         $extra = '';
  3483.         if ($cpu == 'unknown') {
  3484.             $cpu = $parts[$n-2];
  3485.         }
  3486.  
  3487.         switch ($sysname) {
  3488.             case 'AIX' :
  3489.                 $release = "$parts[3].$parts[2]";
  3490.                 break;
  3491.             case 'Windows' :
  3492.                 switch ($parts[1]) {
  3493.                     case '95/98':
  3494.                         $release = '9x';
  3495.                         break;
  3496.                     default:
  3497.                         $release = $parts[1];
  3498.                         break;
  3499.                 }
  3500.                 $cpu = 'i386';
  3501.                 break;
  3502.             case 'Linux' :
  3503.                 $extra = $this->_detectGlibcVersion();
  3504.                 // use only the first two digits from the kernel version
  3505.                 $release = ereg_replace('^([[:digit:]]+\.[[:digit:]]+).*', '\1', $parts[2]);
  3506.                 break;
  3507.             case 'Mac' :
  3508.                 $sysname = 'darwin';
  3509.                 $nodename = $parts[2];
  3510.                 $release = $parts[3];
  3511.                 if ($cpu == 'Macintosh') {
  3512.                     if ($parts[$n - 2] == 'Power') {
  3513.                         $cpu = 'powerpc';
  3514.                     }
  3515.                 }
  3516.                 break;
  3517.             case 'Darwin' :
  3518.                 if ($cpu == 'Macintosh') {
  3519.                     if ($parts[$n - 2] == 'Power') {
  3520.                         $cpu = 'powerpc';
  3521.                     }
  3522.                 }
  3523.                 $release = ereg_replace('^([[:digit:]]+\.[[:digit:]]+).*', '\1', $parts[2]);
  3524.                 break;
  3525.             default:
  3526.                 $release = ereg_replace('-.*', '', $parts[2]);
  3527.                 break;
  3528.         }
  3529.  
  3530.  
  3531.         if (isset($sysmap[$sysname])) {
  3532.             $sysname = $sysmap[$sysname];
  3533.         } else {
  3534.             $sysname = strtolower($sysname);
  3535.         }
  3536.         if (isset($cpumap[$cpu])) {
  3537.             $cpu = $cpumap[$cpu];
  3538.         }
  3539.         return array($sysname, $release, $cpu, $extra, $nodename);
  3540.     }
  3541.  
  3542.     function _detectGlibcVersion()
  3543.     {
  3544.         static $glibc = false;
  3545.         if ($glibc !== false) {
  3546.             return $glibc; // no need to run this multiple times
  3547.         }
  3548.         $major = $minor = 0;
  3549.         include_once 'phar://go-pear.phar/' . "System.php";
  3550.         // Use glibc's <features.h> header file to
  3551.         // get major and minor version number:
  3552.         if (@file_exists('/usr/include/features.h') &&
  3553.               @is_readable('/usr/include/features.h')) {
  3554.             if (!@file_exists('/usr/bin/cpp') || !@is_executable('/usr/bin/cpp')) {
  3555.                 $features_file = fopen('/usr/include/features.h', 'rb');
  3556.                 while (!feof($features_file)) {
  3557.                     $line = fgets($features_file, 8192);
  3558.                     if (!$line || (strpos($line, '#define') === false)) {
  3559.                         continue;
  3560.                     }
  3561.                     if (strpos($line, '__GLIBC__')) {
  3562.                         // major version number #define __GLIBC__ version
  3563.                         $line = preg_split('/\s+/', $line);
  3564.                         $glibc_major = trim($line[2]);
  3565.                         if (isset($glibc_minor)) {
  3566.                             break;
  3567.                         }
  3568.                         continue;
  3569.                     }
  3570.                     if (strpos($line, '__GLIBC_MINOR__'))  {
  3571.                         // got the minor version number
  3572.                         // #define __GLIBC_MINOR__ version
  3573.                         $line = preg_split('/\s+/', $line);
  3574.                         $glibc_minor = trim($line[2]);
  3575.                         if (isset($glibc_major)) {
  3576.                             break;
  3577.                         }
  3578.                         continue;
  3579.                     }
  3580.                 }
  3581.                 fclose($features_file);
  3582.                 if (!isset($glibc_major) || !isset($glibc_minor)) {
  3583.                     return $glibc = '';
  3584.                 }
  3585.                 return $glibc = 'glibc' . trim($glibc_major) . "." . trim($glibc_minor) ;
  3586.             } // no cpp
  3587.             $tmpfile = System::mktemp("glibctest");
  3588.             $fp = fopen($tmpfile, "w");
  3589.             fwrite($fp, "#include <features.h>\n__GLIBC__ __GLIBC_MINOR__\n");
  3590.             fclose($fp);
  3591.             $cpp = popen("/usr/bin/cpp $tmpfile", "r");
  3592.             while ($line = fgets($cpp, 1024)) {
  3593.                 if ($line{0} == '#' || trim($line) == '') {
  3594.                     continue;
  3595.                 }
  3596.                 if (list($major, $minor) = explode(' ', trim($line))) {
  3597.                     break;
  3598.                 }
  3599.             }
  3600.             pclose($cpp);
  3601.             unlink($tmpfile);
  3602.         } // features.h
  3603.         if (!($major && $minor) && @is_link('/lib/libc.so.6')) {
  3604.             // Let's try reading the libc.so.6 symlink
  3605.             if (ereg('^libc-(.*)\.so$', basename(readlink('/lib/libc.so.6')), $matches)) {
  3606.                 list($major, $minor) = explode('.', $matches[1]);
  3607.             }
  3608.         }
  3609.         if (!($major && $minor)) {
  3610.             return $glibc = '';
  3611.         }
  3612.         return $glibc = "glibc{$major}.{$minor}";
  3613.     }
  3614.  
  3615.     function getSignature()
  3616.     {
  3617.         if (empty($this->extra)) {
  3618.             return "{$this->sysname}-{$this->release}-{$this->cpu}";
  3619.         }
  3620.         return "{$this->sysname}-{$this->release}-{$this->cpu}-{$this->extra}";
  3621.     }
  3622.  
  3623.     function getSysname()
  3624.     {
  3625.         return $this->sysname;
  3626.     }
  3627.  
  3628.     function getNodename()
  3629.     {
  3630.         return $this->nodename;
  3631.     }
  3632.  
  3633.     function getCpu()
  3634.     {
  3635.         return $this->cpu;
  3636.     }
  3637.  
  3638.     function getRelease()
  3639.     {
  3640.         return $this->release;
  3641.     }
  3642.  
  3643.     function getExtra()
  3644.     {
  3645.         return $this->extra;
  3646.     }
  3647.  
  3648.     function matchSignature($match)
  3649.     {
  3650.         if (is_array($match)) {
  3651.             $fragments = $match;
  3652.         } else {
  3653.             $fragments = explode('-', $match);
  3654.         }
  3655.         $n = count($fragments);
  3656.         $matches = 0;
  3657.         if ($n > 0) {
  3658.             $matches += $this->_matchFragment($fragments[0], $this->sysname);
  3659.         }
  3660.         if ($n > 1) {
  3661.             $matches += $this->_matchFragment($fragments[1], $this->release);
  3662.         }
  3663.         if ($n > 2) {
  3664.             $matches += $this->_matchFragment($fragments[2], $this->cpu);
  3665.         }
  3666.         if ($n > 3) {
  3667.             $matches += $this->_matchFragment($fragments[3], $this->extra);
  3668.         }
  3669.         return ($matches == $n);
  3670.     }
  3671.  
  3672.     function _matchFragment($fragment, $value)
  3673.     {
  3674.         if (strcspn($fragment, '*?') < strlen($fragment)) {
  3675.             $reg = '^' . str_replace(array('*', '?', '/'), array('.*', '.', '\\/'), $fragment) . '$';
  3676.             return eregi($reg, $value);
  3677.         }
  3678.         return ($fragment == '*' || !strcasecmp($fragment, $value));
  3679.     }
  3680.  
  3681. }
  3682. /*
  3683.  * Local Variables:
  3684.  * indent-tabs-mode: nil
  3685.  * c-basic-offset: 4
  3686.  * End:
  3687.  */
  3688. ?>
  3689. <?php
  3690. /**
  3691.  * PEAR, the PHP Extension and Application Repository
  3692.  *
  3693.  * PEAR class and PEAR_Error class
  3694.  *
  3695.  * PHP versions 4 and 5
  3696.  *
  3697.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  3698.  * that is available through the world-wide-web at the following URI:
  3699.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  3700.  * the PHP License and are unable to obtain it through the web, please
  3701.  * send a note to license@php.net so we can mail you a copy immediately.
  3702.  *
  3703.  * @category   pear
  3704.  * @package    PEAR
  3705.  * @author     Sterling Hughes <sterling@php.net>
  3706.  * @author     Stig Bakken <ssb@php.net>
  3707.  * @author     Tomas V.V.Cox <cox@idecnet.com>
  3708.  * @author     Greg Beaver <cellog@php.net>
  3709.  * @copyright  1997-2008 The PHP Group
  3710.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  3711.  * @version    CVS: $Id: PEAR.php,v 1.104 2008/01/03 20:26:34 cellog Exp $
  3712.  * @link       http://pear.php.net/package/PEAR
  3713.  * @since      File available since Release 0.1
  3714.  */
  3715.  
  3716. /**#@+
  3717.  * ERROR constants
  3718.  */
  3719. define('PEAR_ERROR_RETURN',     1);
  3720. define('PEAR_ERROR_PRINT',      2);
  3721. define('PEAR_ERROR_TRIGGER',    4);
  3722. define('PEAR_ERROR_DIE',        8);
  3723. define('PEAR_ERROR_CALLBACK',  16);
  3724. /**
  3725.  * WARNING: obsolete
  3726.  * @deprecated
  3727.  */
  3728. define('PEAR_ERROR_EXCEPTION', 32);
  3729. /**#@-*/
  3730. define('PEAR_ZE2', (function_exists('version_compare') &&
  3731.                     version_compare(zend_version(), "2-dev", "ge")));
  3732.  
  3733. if (substr(PHP_OS, 0, 3) == 'WIN') {
  3734.     define('OS_WINDOWS', true);
  3735.     define('OS_UNIX',    false);
  3736.     define('PEAR_OS',    'Windows');
  3737. } else {
  3738.     define('OS_WINDOWS', false);
  3739.     define('OS_UNIX',    true);
  3740.     define('PEAR_OS',    'Unix'); // blatant assumption
  3741. }
  3742.  
  3743. // instant backwards compatibility
  3744. if (!defined('PATH_SEPARATOR')) {
  3745.     if (OS_WINDOWS) {
  3746.         define('PATH_SEPARATOR', ';');
  3747.     } else {
  3748.         define('PATH_SEPARATOR', ':');
  3749.     }
  3750. }
  3751.  
  3752. $GLOBALS['_PEAR_default_error_mode']     = PEAR_ERROR_RETURN;
  3753. $GLOBALS['_PEAR_default_error_options']  = E_USER_NOTICE;
  3754. $GLOBALS['_PEAR_destructor_object_list'] = array();
  3755. $GLOBALS['_PEAR_shutdown_funcs']         = array();
  3756. $GLOBALS['_PEAR_error_handler_stack']    = array();
  3757.  
  3758. @ini_set('track_errors', true);
  3759.  
  3760. /**
  3761.  * Base class for other PEAR classes.  Provides rudimentary
  3762.  * emulation of destructors.
  3763.  *
  3764.  * If you want a destructor in your class, inherit PEAR and make a
  3765.  * destructor method called _yourclassname (same name as the
  3766.  * constructor, but with a "_" prefix).  Also, in your constructor you
  3767.  * have to call the PEAR constructor: $this->PEAR();.
  3768.  * The destructor method will be called without parameters.  Note that
  3769.  * at in some SAPI implementations (such as Apache), any output during
  3770.  * the request shutdown (in which destructors are called) seems to be
  3771.  * discarded.  If you need to get any debug information from your
  3772.  * destructor, use error_log(), syslog() or something similar.
  3773.  *
  3774.  * IMPORTANT! To use the emulated destructors you need to create the
  3775.  * objects by reference: $obj =& new PEAR_child;
  3776.  *
  3777.  * @category   pear
  3778.  * @package    PEAR
  3779.  * @author     Stig Bakken <ssb@php.net>
  3780.  * @author     Tomas V.V. Cox <cox@idecnet.com>
  3781.  * @author     Greg Beaver <cellog@php.net>
  3782.  * @copyright  1997-2006 The PHP Group
  3783.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  3784.  * @version    Release: 1.7.1
  3785.  * @link       http://pear.php.net/package/PEAR
  3786.  * @see        PEAR_Error
  3787.  * @since      Class available since PHP 4.0.2
  3788.  * @link        http://pear.php.net/manual/en/core.pear.php#core.pear.pear
  3789.  */
  3790. class PEAR
  3791. {
  3792.     // {{{ properties
  3793.  
  3794.     /**
  3795.      * Whether to enable internal debug messages.
  3796.      *
  3797.      * @var     bool
  3798.      * @access  private
  3799.      */
  3800.     var $_debug = false;
  3801.  
  3802.     /**
  3803.      * Default error mode for this object.
  3804.      *
  3805.      * @var     int
  3806.      * @access  private
  3807.      */
  3808.     var $_default_error_mode = null;
  3809.  
  3810.     /**
  3811.      * Default error options used for this object when error mode
  3812.      * is PEAR_ERROR_TRIGGER.
  3813.      *
  3814.      * @var     int
  3815.      * @access  private
  3816.      */
  3817.     var $_default_error_options = null;
  3818.  
  3819.     /**
  3820.      * Default error handler (callback) for this object, if error mode is
  3821.      * PEAR_ERROR_CALLBACK.
  3822.      *
  3823.      * @var     string
  3824.      * @access  private
  3825.      */
  3826.     var $_default_error_handler = '';
  3827.  
  3828.     /**
  3829.      * Which class to use for error objects.
  3830.      *
  3831.      * @var     string
  3832.      * @access  private
  3833.      */
  3834.     var $_error_class = 'PEAR_Error';
  3835.  
  3836.     /**
  3837.      * An array of expected errors.
  3838.      *
  3839.      * @var     array
  3840.      * @access  private
  3841.      */
  3842.     var $_expected_errors = array();
  3843.  
  3844.     // }}}
  3845.  
  3846.     // {{{ constructor
  3847.  
  3848.     /**
  3849.      * Constructor.  Registers this object in
  3850.      * $_PEAR_destructor_object_list for destructor emulation if a
  3851.      * destructor object exists.
  3852.      *
  3853.      * @param string $error_class  (optional) which class to use for
  3854.      *        error objects, defaults to PEAR_Error.
  3855.      * @access public
  3856.      * @return void
  3857.      */
  3858.     function PEAR($error_class = null)
  3859.     {
  3860.         $classname = strtolower(get_class($this));
  3861.         if ($this->_debug) {
  3862.             print "PEAR constructor called, class=$classname\n";
  3863.         }
  3864.         if ($error_class !== null) {
  3865.             $this->_error_class = $error_class;
  3866.         }
  3867.         while ($classname && strcasecmp($classname, "pear")) {
  3868.             $destructor = "_$classname";
  3869.             if (method_exists($this, $destructor)) {
  3870.                 global $_PEAR_destructor_object_list;
  3871.                 $_PEAR_destructor_object_list[] = &$this;
  3872.                 if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) {
  3873.                     register_shutdown_function("_PEAR_call_destructors");
  3874.                     $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true;
  3875.                 }
  3876.                 break;
  3877.             } else {
  3878.                 $classname = get_parent_class($classname);
  3879.             }
  3880.         }
  3881.     }
  3882.  
  3883.     // }}}
  3884.     // {{{ destructor
  3885.  
  3886.     /**
  3887.      * Destructor (the emulated type of...).  Does nothing right now,
  3888.      * but is included for forward compatibility, so subclass
  3889.      * destructors should always call it.
  3890.      *
  3891.      * See the note in the class desciption about output from
  3892.      * destructors.
  3893.      *
  3894.      * @access public
  3895.      * @return void
  3896.      */
  3897.     function _PEAR() {
  3898.         if ($this->_debug) {
  3899.             printf("PEAR destructor called, class=%s\n", strtolower(get_class($this)));
  3900.         }
  3901.     }
  3902.  
  3903.     // }}}
  3904.     // {{{ getStaticProperty()
  3905.  
  3906.     /**
  3907.     * If you have a class that's mostly/entirely static, and you need static
  3908.     * properties, you can use this method to simulate them. Eg. in your method(s)
  3909.     * do this: $myVar = &PEAR::getStaticProperty('myclass', 'myVar');
  3910.     * You MUST use a reference, or they will not persist!
  3911.     *
  3912.     * @access public
  3913.     * @param  string $class  The calling classname, to prevent clashes
  3914.     * @param  string $var    The variable to retrieve.
  3915.     * @return mixed   A reference to the variable. If not set it will be
  3916.     *                 auto initialised to NULL.
  3917.     */
  3918.     function &getStaticProperty($class, $var)
  3919.     {
  3920.         static $properties;
  3921.         if (!isset($properties[$class])) {
  3922.             $properties[$class] = array();
  3923.         }
  3924.         if (!array_key_exists($var, $properties[$class])) {
  3925.             $properties[$class][$var] = null;
  3926.         }
  3927.         return $properties[$class][$var];
  3928.     }
  3929.  
  3930.     // }}}
  3931.     // {{{ registerShutdownFunc()
  3932.  
  3933.     /**
  3934.     * Use this function to register a shutdown method for static
  3935.     * classes.
  3936.     *
  3937.     * @access public
  3938.     * @param  mixed $func  The function name (or array of class/method) to call
  3939.     * @param  mixed $args  The arguments to pass to the function
  3940.     * @return void
  3941.     */
  3942.     function registerShutdownFunc($func, $args = array())
  3943.     {
  3944.         // if we are called statically, there is a potential
  3945.         // that no shutdown func is registered.  Bug #6445
  3946.         if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) {
  3947.             register_shutdown_function("_PEAR_call_destructors");
  3948.             $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true;
  3949.         }
  3950.         $GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args);
  3951.     }
  3952.  
  3953.     // }}}
  3954.     // {{{ isError()
  3955.  
  3956.     /**
  3957.      * Tell whether a value is a PEAR error.
  3958.      *
  3959.      * @param   mixed $data   the value to test
  3960.      * @param   int   $code   if $data is an error object, return true
  3961.      *                        only if $code is a string and
  3962.      *                        $obj->getMessage() == $code or
  3963.      *                        $code is an integer and $obj->getCode() == $code
  3964.      * @access  public
  3965.      * @return  bool    true if parameter is an error
  3966.      */
  3967.     function isError($data, $code = null)
  3968.     {
  3969.         if (is_a($data, 'PEAR_Error')) {
  3970.             if (is_null($code)) {
  3971.                 return true;
  3972.             } elseif (is_string($code)) {
  3973.                 return $data->getMessage() == $code;
  3974.             } else {
  3975.                 return $data->getCode() == $code;
  3976.             }
  3977.         }
  3978.         return false;
  3979.     }
  3980.  
  3981.     // }}}
  3982.     // {{{ setErrorHandling()
  3983.  
  3984.     /**
  3985.      * Sets how errors generated by this object should be handled.
  3986.      * Can be invoked both in objects and statically.  If called
  3987.      * statically, setErrorHandling sets the default behaviour for all
  3988.      * PEAR objects.  If called in an object, setErrorHandling sets
  3989.      * the default behaviour for that object.
  3990.      *
  3991.      * @param int $mode
  3992.      *        One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT,
  3993.      *        PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE,
  3994.      *        PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION.
  3995.      *
  3996.      * @param mixed $options
  3997.      *        When $mode is PEAR_ERROR_TRIGGER, this is the error level (one
  3998.      *        of E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR).
  3999.      *
  4000.      *        When $mode is PEAR_ERROR_CALLBACK, this parameter is expected
  4001.      *        to be the callback function or method.  A callback
  4002.      *        function is a string with the name of the function, a
  4003.      *        callback method is an array of two elements: the element
  4004.      *        at index 0 is the object, and the element at index 1 is
  4005.      *        the name of the method to call in the object.
  4006.      *
  4007.      *        When $mode is PEAR_ERROR_PRINT or PEAR_ERROR_DIE, this is
  4008.      *        a printf format string used when printing the error
  4009.      *        message.
  4010.      *
  4011.      * @access public
  4012.      * @return void
  4013.      * @see PEAR_ERROR_RETURN
  4014.      * @see PEAR_ERROR_PRINT
  4015.      * @see PEAR_ERROR_TRIGGER
  4016.      * @see PEAR_ERROR_DIE
  4017.      * @see PEAR_ERROR_CALLBACK
  4018.      * @see PEAR_ERROR_EXCEPTION
  4019.      *
  4020.      * @since PHP 4.0.5
  4021.      */
  4022.  
  4023.     function setErrorHandling($mode = null, $options = null)
  4024.     {
  4025.         if (isset($this) && is_a($this, 'PEAR')) {
  4026.             $setmode     = &$this->_default_error_mode;
  4027.             $setoptions  = &$this->_default_error_options;
  4028.         } else {
  4029.             $setmode     = &$GLOBALS['_PEAR_default_error_mode'];
  4030.             $setoptions  = &$GLOBALS['_PEAR_default_error_options'];
  4031.         }
  4032.  
  4033.         switch ($mode) {
  4034.             case PEAR_ERROR_EXCEPTION:
  4035.             case PEAR_ERROR_RETURN:
  4036.             case PEAR_ERROR_PRINT:
  4037.             case PEAR_ERROR_TRIGGER:
  4038.             case PEAR_ERROR_DIE:
  4039.             case null:
  4040.                 $setmode = $mode;
  4041.                 $setoptions = $options;
  4042.                 break;
  4043.  
  4044.             case PEAR_ERROR_CALLBACK:
  4045.                 $setmode = $mode;
  4046.                 // class/object method callback
  4047.                 if (is_callable($options)) {
  4048.                     $setoptions = $options;
  4049.                 } else {
  4050.                     trigger_error("invalid error callback", E_USER_WARNING);
  4051.                 }
  4052.                 break;
  4053.  
  4054.             default:
  4055.                 trigger_error("invalid error mode", E_USER_WARNING);
  4056.                 break;
  4057.         }
  4058.     }
  4059.  
  4060.     // }}}
  4061.     // {{{ expectError()
  4062.  
  4063.     /**
  4064.      * This method is used to tell which errors you expect to get.
  4065.      * Expected errors are always returned with error mode
  4066.      * PEAR_ERROR_RETURN.  Expected error codes are stored in a stack,
  4067.      * and this method pushes a new element onto it.  The list of
  4068.      * expected errors are in effect until they are popped off the
  4069.      * stack with the popExpect() method.
  4070.      *
  4071.      * Note that this method can not be called statically
  4072.      *
  4073.      * @param mixed $code a single error code or an array of error codes to expect
  4074.      *
  4075.      * @return int     the new depth of the "expected errors" stack
  4076.      * @access public
  4077.      */
  4078.     function expectError($code = '*')
  4079.     {
  4080.         if (is_array($code)) {
  4081.             array_push($this->_expected_errors, $code);
  4082.         } else {
  4083.             array_push($this->_expected_errors, array($code));
  4084.         }
  4085.         return sizeof($this->_expected_errors);
  4086.     }
  4087.  
  4088.     // }}}
  4089.     // {{{ popExpect()
  4090.  
  4091.     /**
  4092.      * This method pops one element off the expected error codes
  4093.      * stack.
  4094.      *
  4095.      * @return array   the list of error codes that were popped
  4096.      */
  4097.     function popExpect()
  4098.     {
  4099.         return array_pop($this->_expected_errors);
  4100.     }
  4101.  
  4102.     // }}}
  4103.     // {{{ _checkDelExpect()
  4104.  
  4105.     /**
  4106.      * This method checks unsets an error code if available
  4107.      *
  4108.      * @param mixed error code
  4109.      * @return bool true if the error code was unset, false otherwise
  4110.      * @access private
  4111.      * @since PHP 4.3.0
  4112.      */
  4113.     function _checkDelExpect($error_code)
  4114.     {
  4115.         $deleted = false;
  4116.  
  4117.         foreach ($this->_expected_errors AS $key => $error_array) {
  4118.             if (in_array($error_code, $error_array)) {
  4119.                 unset($this->_expected_errors[$key][array_search($error_code, $error_array)]);
  4120.                 $deleted = true;
  4121.             }
  4122.  
  4123.             // clean up empty arrays
  4124.             if (0 == count($this->_expected_errors[$key])) {
  4125.                 unset($this->_expected_errors[$key]);
  4126.             }
  4127.         }
  4128.         return $deleted;
  4129.     }
  4130.  
  4131.     // }}}
  4132.     // {{{ delExpect()
  4133.  
  4134.     /**
  4135.      * This method deletes all occurences of the specified element from
  4136.      * the expected error codes stack.
  4137.      *
  4138.      * @param  mixed $error_code error code that should be deleted
  4139.      * @return mixed list of error codes that were deleted or error
  4140.      * @access public
  4141.      * @since PHP 4.3.0
  4142.      */
  4143.     function delExpect($error_code)
  4144.     {
  4145.         $deleted = false;
  4146.  
  4147.         if ((is_array($error_code) && (0 != count($error_code)))) {
  4148.             // $error_code is a non-empty array here;
  4149.             // we walk through it trying to unset all
  4150.             // values
  4151.             foreach($error_code as $key => $error) {
  4152.                 if ($this->_checkDelExpect($error)) {
  4153.                     $deleted =  true;
  4154.                 } else {
  4155.                     $deleted = false;
  4156.                 }
  4157.             }
  4158.             return $deleted ? true : PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME
  4159.         } elseif (!empty($error_code)) {
  4160.             // $error_code comes alone, trying to unset it
  4161.             if ($this->_checkDelExpect($error_code)) {
  4162.                 return true;
  4163.             } else {
  4164.                 return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME
  4165.             }
  4166.         } else {
  4167.             // $error_code is empty
  4168.             return PEAR::raiseError("The expected error you submitted is empty"); // IMPROVE ME
  4169.         }
  4170.     }
  4171.  
  4172.     // }}}
  4173.     // {{{ raiseError()
  4174.  
  4175.     /**
  4176.      * This method is a wrapper that returns an instance of the
  4177.      * configured error class with this object's default error
  4178.      * handling applied.  If the $mode and $options parameters are not
  4179.      * specified, the object's defaults are used.
  4180.      *
  4181.      * @param mixed $message a text error message or a PEAR error object
  4182.      *
  4183.      * @param int $code      a numeric error code (it is up to your class
  4184.      *                  to define these if you want to use codes)
  4185.      *
  4186.      * @param int $mode      One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT,
  4187.      *                  PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE,
  4188.      *                  PEAR_ERROR_CALLBACK, PEAR_ERROR_EXCEPTION.
  4189.      *
  4190.      * @param mixed $options If $mode is PEAR_ERROR_TRIGGER, this parameter
  4191.      *                  specifies the PHP-internal error level (one of
  4192.      *                  E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR).
  4193.      *                  If $mode is PEAR_ERROR_CALLBACK, this
  4194.      *                  parameter specifies the callback function or
  4195.      *                  method.  In other error modes this parameter
  4196.      *                  is ignored.
  4197.      *
  4198.      * @param string $userinfo If you need to pass along for example debug
  4199.      *                  information, this parameter is meant for that.
  4200.      *
  4201.      * @param string $error_class The returned error object will be
  4202.      *                  instantiated from this class, if specified.
  4203.      *
  4204.      * @param bool $skipmsg If true, raiseError will only pass error codes,
  4205.      *                  the error message parameter will be dropped.
  4206.      *
  4207.      * @access public
  4208.      * @return object   a PEAR error object
  4209.      * @see PEAR::setErrorHandling
  4210.      * @since PHP 4.0.5
  4211.      */
  4212.     function &raiseError($message = null,
  4213.                          $code = null,
  4214.                          $mode = null,
  4215.                          $options = null,
  4216.                          $userinfo = null,
  4217.                          $error_class = null,
  4218.                          $skipmsg = false)
  4219.     {
  4220.         // The error is yet a PEAR error object
  4221.         if (is_object($message)) {
  4222.             $code        = $message->getCode();
  4223.             $userinfo    = $message->getUserInfo();
  4224.             $error_class = $message->getType();
  4225.             $message->error_message_prefix = '';
  4226.             $message     = $message->getMessage();
  4227.         }
  4228.  
  4229.         if (isset($this) && isset($this->_expected_errors) && sizeof($this->_expected_errors) > 0 && sizeof($exp = end($this->_expected_errors))) {
  4230.             if ($exp[0] == "*" ||
  4231.                 (is_int(reset($exp)) && in_array($code, $exp)) ||
  4232.                 (is_string(reset($exp)) && in_array($message, $exp))) {
  4233.                 $mode = PEAR_ERROR_RETURN;
  4234.             }
  4235.         }
  4236.         // No mode given, try global ones
  4237.         if ($mode === null) {
  4238.             // Class error handler
  4239.             if (isset($this) && isset($this->_default_error_mode)) {
  4240.                 $mode    = $this->_default_error_mode;
  4241.                 $options = $this->_default_error_options;
  4242.             // Global error handler
  4243.             } elseif (isset($GLOBALS['_PEAR_default_error_mode'])) {
  4244.                 $mode    = $GLOBALS['_PEAR_default_error_mode'];
  4245.                 $options = $GLOBALS['_PEAR_default_error_options'];
  4246.             }
  4247.         }
  4248.  
  4249.         if ($error_class !== null) {
  4250.             $ec = $error_class;
  4251.         } elseif (isset($this) && isset($this->_error_class)) {
  4252.             $ec = $this->_error_class;
  4253.         } else {
  4254.             $ec = 'PEAR_Error';
  4255.         }
  4256.         if (intval(PHP_VERSION) < 5) {
  4257.             // little non-eval hack to fix bug #12147
  4258.             include 'phar://go-pear.phar/' . 'PEAR/FixPHP5PEARWarnings.php';
  4259.             return $a;
  4260.         }
  4261.         if ($skipmsg) {
  4262.             $a = new $ec($code, $mode, $options, $userinfo);
  4263.         } else {
  4264.             $a = new $ec($message, $code, $mode, $options, $userinfo);
  4265.         }
  4266.         return $a;
  4267.     }
  4268.  
  4269.     // }}}
  4270.     // {{{ throwError()
  4271.  
  4272.     /**
  4273.      * Simpler form of raiseError with fewer options.  In most cases
  4274.      * message, code and userinfo are enough.
  4275.      *
  4276.      * @param string $message
  4277.      *
  4278.      */
  4279.     function &throwError($message = null,
  4280.                          $code = null,
  4281.                          $userinfo = null)
  4282.     {
  4283.         if (isset($this) && is_a($this, 'PEAR')) {
  4284.             $a = &$this->raiseError($message, $code, null, null, $userinfo);
  4285.             return $a;
  4286.         } else {
  4287.             $a = &PEAR::raiseError($message, $code, null, null, $userinfo);
  4288.             return $a;
  4289.         }
  4290.     }
  4291.  
  4292.     // }}}
  4293.     function staticPushErrorHandling($mode, $options = null)
  4294.     {
  4295.         $stack = &$GLOBALS['_PEAR_error_handler_stack'];
  4296.         $def_mode    = &$GLOBALS['_PEAR_default_error_mode'];
  4297.         $def_options = &$GLOBALS['_PEAR_default_error_options'];
  4298.         $stack[] = array($def_mode, $def_options);
  4299.         switch ($mode) {
  4300.             case PEAR_ERROR_EXCEPTION:
  4301.             case PEAR_ERROR_RETURN:
  4302.             case PEAR_ERROR_PRINT:
  4303.             case PEAR_ERROR_TRIGGER:
  4304.             case PEAR_ERROR_DIE:
  4305.             case null:
  4306.                 $def_mode = $mode;
  4307.                 $def_options = $options;
  4308.                 break;
  4309.  
  4310.             case PEAR_ERROR_CALLBACK:
  4311.                 $def_mode = $mode;
  4312.                 // class/object method callback
  4313.                 if (is_callable($options)) {
  4314.                     $def_options = $options;
  4315.                 } else {
  4316.                     trigger_error("invalid error callback", E_USER_WARNING);
  4317.                 }
  4318.                 break;
  4319.  
  4320.             default:
  4321.                 trigger_error("invalid error mode", E_USER_WARNING);
  4322.                 break;
  4323.         }
  4324.         $stack[] = array($mode, $options);
  4325.         return true;
  4326.     }
  4327.  
  4328.     function staticPopErrorHandling()
  4329.     {
  4330.         $stack = &$GLOBALS['_PEAR_error_handler_stack'];
  4331.         $setmode     = &$GLOBALS['_PEAR_default_error_mode'];
  4332.         $setoptions  = &$GLOBALS['_PEAR_default_error_options'];
  4333.         array_pop($stack);
  4334.         list($mode, $options) = $stack[sizeof($stack) - 1];
  4335.         array_pop($stack);
  4336.         switch ($mode) {
  4337.             case PEAR_ERROR_EXCEPTION:
  4338.             case PEAR_ERROR_RETURN:
  4339.             case PEAR_ERROR_PRINT:
  4340.             case PEAR_ERROR_TRIGGER:
  4341.             case PEAR_ERROR_DIE:
  4342.             case null:
  4343.                 $setmode = $mode;
  4344.                 $setoptions = $options;
  4345.                 break;
  4346.  
  4347.             case PEAR_ERROR_CALLBACK:
  4348.                 $setmode = $mode;
  4349.                 // class/object method callback
  4350.                 if (is_callable($options)) {
  4351.                     $setoptions = $options;
  4352.                 } else {
  4353.                     trigger_error("invalid error callback", E_USER_WARNING);
  4354.                 }
  4355.                 break;
  4356.  
  4357.             default:
  4358.                 trigger_error("invalid error mode", E_USER_WARNING);
  4359.                 break;
  4360.         }
  4361.         return true;
  4362.     }
  4363.  
  4364.     // {{{ pushErrorHandling()
  4365.  
  4366.     /**
  4367.      * Push a new error handler on top of the error handler options stack. With this
  4368.      * you can easily override the actual error handler for some code and restore
  4369.      * it later with popErrorHandling.
  4370.      *
  4371.      * @param mixed $mode (same as setErrorHandling)
  4372.      * @param mixed $options (same as setErrorHandling)
  4373.      *
  4374.      * @return bool Always true
  4375.      *
  4376.      * @see PEAR::setErrorHandling
  4377.      */
  4378.     function pushErrorHandling($mode, $options = null)
  4379.     {
  4380.         $stack = &$GLOBALS['_PEAR_error_handler_stack'];
  4381.         if (isset($this) && is_a($this, 'PEAR')) {
  4382.             $def_mode    = &$this->_default_error_mode;
  4383.             $def_options = &$this->_default_error_options;
  4384.         } else {
  4385.             $def_mode    = &$GLOBALS['_PEAR_default_error_mode'];
  4386.             $def_options = &$GLOBALS['_PEAR_default_error_options'];
  4387.         }
  4388.         $stack[] = array($def_mode, $def_options);
  4389.  
  4390.         if (isset($this) && is_a($this, 'PEAR')) {
  4391.             $this->setErrorHandling($mode, $options);
  4392.         } else {
  4393.             PEAR::setErrorHandling($mode, $options);
  4394.         }
  4395.         $stack[] = array($mode, $options);
  4396.         return true;
  4397.     }
  4398.  
  4399.     // }}}
  4400.     // {{{ popErrorHandling()
  4401.  
  4402.     /**
  4403.     * Pop the last error handler used
  4404.     *
  4405.     * @return bool Always true
  4406.     *
  4407.     * @see PEAR::pushErrorHandling
  4408.     */
  4409.     function popErrorHandling()
  4410.     {
  4411.         $stack = &$GLOBALS['_PEAR_error_handler_stack'];
  4412.         array_pop($stack);
  4413.         list($mode, $options) = $stack[sizeof($stack) - 1];
  4414.         array_pop($stack);
  4415.         if (isset($this) && is_a($this, 'PEAR')) {
  4416.             $this->setErrorHandling($mode, $options);
  4417.         } else {
  4418.             PEAR::setErrorHandling($mode, $options);
  4419.         }
  4420.         return true;
  4421.     }
  4422.  
  4423.     // }}}
  4424.     // {{{ loadExtension()
  4425.  
  4426.     /**
  4427.     * OS independant PHP extension load. Remember to take care
  4428.     * on the correct extension name for case sensitive OSes.
  4429.     *
  4430.     * @param string $ext The extension name
  4431.     * @return bool Success or not on the dl() call
  4432.     */
  4433.     function loadExtension($ext)
  4434.     {
  4435.         if (!extension_loaded($ext)) {
  4436.             // if either returns true dl() will produce a FATAL error, stop that
  4437.             if ((ini_get('enable_dl') != 1) || (ini_get('safe_mode') == 1)) {
  4438.                 return false;
  4439.             }
  4440.             if (OS_WINDOWS) {
  4441.                 $suffix = '.dll';
  4442.             } elseif (PHP_OS == 'HP-UX') {
  4443.                 $suffix = '.sl';
  4444.             } elseif (PHP_OS == 'AIX') {
  4445.                 $suffix = '.a';
  4446.             } elseif (PHP_OS == 'OSX') {
  4447.                 $suffix = '.bundle';
  4448.             } else {
  4449.                 $suffix = '.so';
  4450.             }
  4451.             return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix);
  4452.         }
  4453.         return true;
  4454.     }
  4455.  
  4456.     // }}}
  4457. }
  4458.  
  4459. // {{{ _PEAR_call_destructors()
  4460.  
  4461. function _PEAR_call_destructors()
  4462. {
  4463.     global $_PEAR_destructor_object_list;
  4464.     if (is_array($_PEAR_destructor_object_list) &&
  4465.         sizeof($_PEAR_destructor_object_list))
  4466.     {
  4467.         reset($_PEAR_destructor_object_list);
  4468.         if (PEAR::getStaticProperty('PEAR', 'destructlifo')) {
  4469.             $_PEAR_destructor_object_list = array_reverse($_PEAR_destructor_object_list);
  4470.         }
  4471.         while (list($k, $objref) = each($_PEAR_destructor_object_list)) {
  4472.             $classname = get_class($objref);
  4473.             while ($classname) {
  4474.                 $destructor = "_$classname";
  4475.                 if (method_exists($objref, $destructor)) {
  4476.                     $objref->$destructor();
  4477.                     break;
  4478.                 } else {
  4479.                     $classname = get_parent_class($classname);
  4480.                 }
  4481.             }
  4482.         }
  4483.         // Empty the object list to ensure that destructors are
  4484.         // not called more than once.
  4485.         $_PEAR_destructor_object_list = array();
  4486.     }
  4487.  
  4488.     // Now call the shutdown functions
  4489.     if (is_array($GLOBALS['_PEAR_shutdown_funcs']) AND !empty($GLOBALS['_PEAR_shutdown_funcs'])) {
  4490.         foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) {
  4491.             call_user_func_array($value[0], $value[1]);
  4492.         }
  4493.     }
  4494. }
  4495.  
  4496. // }}}
  4497. /**
  4498.  * Standard PEAR error class for PHP 4
  4499.  *
  4500.  * This class is supserseded by {@link PEAR_Exception} in PHP 5
  4501.  *
  4502.  * @category   pear
  4503.  * @package    PEAR
  4504.  * @author     Stig Bakken <ssb@php.net>
  4505.  * @author     Tomas V.V. Cox <cox@idecnet.com>
  4506.  * @author     Gregory Beaver <cellog@php.net>
  4507.  * @copyright  1997-2006 The PHP Group
  4508.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  4509.  * @version    Release: 1.7.1
  4510.  * @link       http://pear.php.net/manual/en/core.pear.pear-error.php
  4511.  * @see        PEAR::raiseError(), PEAR::throwError()
  4512.  * @since      Class available since PHP 4.0.2
  4513.  */
  4514. class PEAR_Error
  4515. {
  4516.     // {{{ properties
  4517.  
  4518.     var $error_message_prefix = '';
  4519.     var $mode                 = PEAR_ERROR_RETURN;
  4520.     var $level                = E_USER_NOTICE;
  4521.     var $code                 = -1;
  4522.     var $message              = '';
  4523.     var $userinfo             = '';
  4524.     var $backtrace            = null;
  4525.  
  4526.     // }}}
  4527.     // {{{ constructor
  4528.  
  4529.     /**
  4530.      * PEAR_Error constructor
  4531.      *
  4532.      * @param string $message  message
  4533.      *
  4534.      * @param int $code     (optional) error code
  4535.      *
  4536.      * @param int $mode     (optional) error mode, one of: PEAR_ERROR_RETURN,
  4537.      * PEAR_ERROR_PRINT, PEAR_ERROR_DIE, PEAR_ERROR_TRIGGER,
  4538.      * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION
  4539.      *
  4540.      * @param mixed $options   (optional) error level, _OR_ in the case of
  4541.      * PEAR_ERROR_CALLBACK, the callback function or object/method
  4542.      * tuple.
  4543.      *
  4544.      * @param string $userinfo (optional) additional user/debug info
  4545.      *
  4546.      * @access public
  4547.      *
  4548.      */
  4549.     function PEAR_Error($message = 'unknown error', $code = null,
  4550.                         $mode = null, $options = null, $userinfo = null)
  4551.     {
  4552.         if ($mode === null) {
  4553.             $mode = PEAR_ERROR_RETURN;
  4554.         }
  4555.         $this->message   = $message;
  4556.         $this->code      = $code;
  4557.         $this->mode      = $mode;
  4558.         $this->userinfo  = $userinfo;
  4559.         if (!PEAR::getStaticProperty('PEAR_Error', 'skiptrace')) {
  4560.             $this->backtrace = debug_backtrace();
  4561.             if (isset($this->backtrace[0]) && isset($this->backtrace[0]['object'])) {
  4562.                 unset($this->backtrace[0]['object']);
  4563.             }
  4564.         }
  4565.         if ($mode & PEAR_ERROR_CALLBACK) {
  4566.             $this->level = E_USER_NOTICE;
  4567.             $this->callback = $options;
  4568.         } else {
  4569.             if ($options === null) {
  4570.                 $options = E_USER_NOTICE;
  4571.             }
  4572.             $this->level = $options;
  4573.             $this->callback = null;
  4574.         }
  4575.         if ($this->mode & PEAR_ERROR_PRINT) {
  4576.             if (is_null($options) || is_int($options)) {
  4577.                 $format = "%s";
  4578.             } else {
  4579.                 $format = $options;
  4580.             }
  4581.             printf($format, $this->getMessage());
  4582.         }
  4583.         if ($this->mode & PEAR_ERROR_TRIGGER) {
  4584.             trigger_error($this->getMessage(), $this->level);
  4585.         }
  4586.         if ($this->mode & PEAR_ERROR_DIE) {
  4587.             $msg = $this->getMessage();
  4588.             if (is_null($options) || is_int($options)) {
  4589.                 $format = "%s";
  4590.                 if (substr($msg, -1) != "\n") {
  4591.                     $msg .= "\n";
  4592.                 }
  4593.             } else {
  4594.                 $format = $options;
  4595.             }
  4596.             die(sprintf($format, $msg));
  4597.         }
  4598.         if ($this->mode & PEAR_ERROR_CALLBACK) {
  4599.             if (is_callable($this->callback)) {
  4600.                 call_user_func($this->callback, $this);
  4601.             }
  4602.         }
  4603.         if ($this->mode & PEAR_ERROR_EXCEPTION) {
  4604.             trigger_error("PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_Exception for exceptions", E_USER_WARNING);
  4605.             eval('$e = new Exception($this->message, $this->code);throw($e);');
  4606.         }
  4607.     }
  4608.  
  4609.     // }}}
  4610.     // {{{ getMode()
  4611.  
  4612.     /**
  4613.      * Get the error mode from an error object.
  4614.      *
  4615.      * @return int error mode
  4616.      * @access public
  4617.      */
  4618.     function getMode() {
  4619.         return $this->mode;
  4620.     }
  4621.  
  4622.     // }}}
  4623.     // {{{ getCallback()
  4624.  
  4625.     /**
  4626.      * Get the callback function/method from an error object.
  4627.      *
  4628.      * @return mixed callback function or object/method array
  4629.      * @access public
  4630.      */
  4631.     function getCallback() {
  4632.         return $this->callback;
  4633.     }
  4634.  
  4635.     // }}}
  4636.     // {{{ getMessage()
  4637.  
  4638.  
  4639.     /**
  4640.      * Get the error message from an error object.
  4641.      *
  4642.      * @return  string  full error message
  4643.      * @access public
  4644.      */
  4645.     function getMessage()
  4646.     {
  4647.         return ($this->error_message_prefix . $this->message);
  4648.     }
  4649.  
  4650.  
  4651.     // }}}
  4652.     // {{{ getCode()
  4653.  
  4654.     /**
  4655.      * Get error code from an error object
  4656.      *
  4657.      * @return int error code
  4658.      * @access public
  4659.      */
  4660.      function getCode()
  4661.      {
  4662.         return $this->code;
  4663.      }
  4664.  
  4665.     // }}}
  4666.     // {{{ getType()
  4667.  
  4668.     /**
  4669.      * Get the name of this error/exception.
  4670.      *
  4671.      * @return string error/exception name (type)
  4672.      * @access public
  4673.      */
  4674.     function getType()
  4675.     {
  4676.         return get_class($this);
  4677.     }
  4678.  
  4679.     // }}}
  4680.     // {{{ getUserInfo()
  4681.  
  4682.     /**
  4683.      * Get additional user-supplied information.
  4684.      *
  4685.      * @return string user-supplied information
  4686.      * @access public
  4687.      */
  4688.     function getUserInfo()
  4689.     {
  4690.         return $this->userinfo;
  4691.     }
  4692.  
  4693.     // }}}
  4694.     // {{{ getDebugInfo()
  4695.  
  4696.     /**
  4697.      * Get additional debug information supplied by the application.
  4698.      *
  4699.      * @return string debug information
  4700.      * @access public
  4701.      */
  4702.     function getDebugInfo()
  4703.     {
  4704.         return $this->getUserInfo();
  4705.     }
  4706.  
  4707.     // }}}
  4708.     // {{{ getBacktrace()
  4709.  
  4710.     /**
  4711.      * Get the call backtrace from where the error was generated.
  4712.      * Supported with PHP 4.3.0 or newer.
  4713.      *
  4714.      * @param int $frame (optional) what frame to fetch
  4715.      * @return array Backtrace, or NULL if not available.
  4716.      * @access public
  4717.      */
  4718.     function getBacktrace($frame = null)
  4719.     {
  4720.         if (defined('PEAR_IGNORE_BACKTRACE')) {
  4721.             return null;
  4722.         }
  4723.         if ($frame === null) {
  4724.             return $this->backtrace;
  4725.         }
  4726.         return $this->backtrace[$frame];
  4727.     }
  4728.  
  4729.     // }}}
  4730.     // {{{ addUserInfo()
  4731.  
  4732.     function addUserInfo($info)
  4733.     {
  4734.         if (empty($this->userinfo)) {
  4735.             $this->userinfo = $info;
  4736.         } else {
  4737.             $this->userinfo .= " ** $info";
  4738.         }
  4739.     }
  4740.  
  4741.     // }}}
  4742.     // {{{ toString()
  4743.     function __toString()
  4744.     {
  4745.         return $this->getMessage();
  4746.     }
  4747.     // }}}
  4748.     // {{{ toString()
  4749.  
  4750.     /**
  4751.      * Make a string representation of this object.
  4752.      *
  4753.      * @return string a string with an object summary
  4754.      * @access public
  4755.      */
  4756.     function toString() {
  4757.         $modes = array();
  4758.         $levels = array(E_USER_NOTICE  => 'notice',
  4759.                         E_USER_WARNING => 'warning',
  4760.                         E_USER_ERROR   => 'error');
  4761.         if ($this->mode & PEAR_ERROR_CALLBACK) {
  4762.             if (is_array($this->callback)) {
  4763.                 $callback = (is_object($this->callback[0]) ?
  4764.                     strtolower(get_class($this->callback[0])) :
  4765.                     $this->callback[0]) . '::' .
  4766.                     $this->callback[1];
  4767.             } else {
  4768.                 $callback = $this->callback;
  4769.             }
  4770.             return sprintf('[%s: message="%s" code=%d mode=callback '.
  4771.                            'callback=%s prefix="%s" info="%s"]',
  4772.                            strtolower(get_class($this)), $this->message, $this->code,
  4773.                            $callback, $this->error_message_prefix,
  4774.                            $this->userinfo);
  4775.         }
  4776.         if ($this->mode & PEAR_ERROR_PRINT) {
  4777.             $modes[] = 'print';
  4778.         }
  4779.         if ($this->mode & PEAR_ERROR_TRIGGER) {
  4780.             $modes[] = 'trigger';
  4781.         }
  4782.         if ($this->mode & PEAR_ERROR_DIE) {
  4783.             $modes[] = 'die';
  4784.         }
  4785.         if ($this->mode & PEAR_ERROR_RETURN) {
  4786.             $modes[] = 'return';
  4787.         }
  4788.         return sprintf('[%s: message="%s" code=%d mode=%s level=%s '.
  4789.                        'prefix="%s" info="%s"]',
  4790.                        strtolower(get_class($this)), $this->message, $this->code,
  4791.                        implode("|", $modes), $levels[$this->level],
  4792.                        $this->error_message_prefix,
  4793.                        $this->userinfo);
  4794.     }
  4795.  
  4796.     // }}}
  4797. }
  4798.  
  4799. /*
  4800.  * Local Variables:
  4801.  * mode: php
  4802.  * tab-width: 4
  4803.  * c-basic-offset: 4
  4804.  * End:
  4805.  */
  4806. ?>
  4807. <?php
  4808. /**
  4809.  * PEAR_ChannelFile, the channel handling class
  4810.  *
  4811.  * PHP versions 4 and 5
  4812.  *
  4813.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  4814.  * that is available through the world-wide-web at the following URI:
  4815.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  4816.  * the PHP License and are unable to obtain it through the web, please
  4817.  * send a note to license@php.net so we can mail you a copy immediately.
  4818.  *
  4819.  * @category   pear
  4820.  * @package    PEAR
  4821.  * @author     Greg Beaver <cellog@php.net>
  4822.  * @copyright  1997-2008 The PHP Group
  4823.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  4824.  * @version    CVS: $Id: ChannelFile.php,v 1.80 2008/01/03 20:26:34 cellog Exp $
  4825.  * @link       http://pear.php.net/package/PEAR
  4826.  * @since      File available since Release 1.4.0a1
  4827.  */
  4828.  
  4829. /**
  4830.  * Needed for error handling
  4831.  */
  4832. require_once 'phar://go-pear.phar/' . 'PEAR/ErrorStack.php';
  4833. require_once 'phar://go-pear.phar/' . 'PEAR/XMLParser.php';
  4834. require_once 'phar://go-pear.phar/' . 'PEAR/Common.php';
  4835.  
  4836. /**
  4837.  * Error code if the channel.xml <channel> tag does not contain a valid version
  4838.  */
  4839. define('PEAR_CHANNELFILE_ERROR_NO_VERSION', 1);
  4840. /**
  4841.  * Error code if the channel.xml <channel> tag version is not supported (version 1.0 is the only supported version,
  4842.  * currently
  4843.  */
  4844. define('PEAR_CHANNELFILE_ERROR_INVALID_VERSION', 2);
  4845.  
  4846. /**
  4847.  * Error code if parsing is attempted with no xml extension
  4848.  */
  4849. define('PEAR_CHANNELFILE_ERROR_NO_XML_EXT', 3);
  4850.  
  4851. /**
  4852.  * Error code if creating the xml parser resource fails
  4853.  */
  4854. define('PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER', 4);
  4855.  
  4856. /**
  4857.  * Error code used for all sax xml parsing errors
  4858.  */
  4859. define('PEAR_CHANNELFILE_ERROR_PARSER_ERROR', 5);
  4860.  
  4861. /**#@+
  4862.  * Validation errors
  4863.  */
  4864. /**
  4865.  * Error code when channel name is missing
  4866.  */
  4867. define('PEAR_CHANNELFILE_ERROR_NO_NAME', 6);
  4868. /**
  4869.  * Error code when channel name is invalid
  4870.  */
  4871. define('PEAR_CHANNELFILE_ERROR_INVALID_NAME', 7);
  4872. /**
  4873.  * Error code when channel summary is missing
  4874.  */
  4875. define('PEAR_CHANNELFILE_ERROR_NO_SUMMARY', 8);
  4876. /**
  4877.  * Error code when channel summary is multi-line
  4878.  */
  4879. define('PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY', 9);
  4880. /**
  4881.  * Error code when channel server is missing for xmlrpc or soap protocol
  4882.  */
  4883. define('PEAR_CHANNELFILE_ERROR_NO_HOST', 10);
  4884. /**
  4885.  * Error code when channel server is invalid for xmlrpc or soap protocol
  4886.  */
  4887. define('PEAR_CHANNELFILE_ERROR_INVALID_HOST', 11);
  4888. /**
  4889.  * Error code when a mirror name is invalid
  4890.  */
  4891. define('PEAR_CHANNELFILE_ERROR_INVALID_MIRROR', 21);
  4892. /**
  4893.  * Error code when a mirror type is invalid
  4894.  */
  4895. define('PEAR_CHANNELFILE_ERROR_INVALID_MIRRORTYPE', 22);
  4896. /**
  4897.  * Error code when an attempt is made to generate xml, but the parsed content is invalid
  4898.  */
  4899. define('PEAR_CHANNELFILE_ERROR_INVALID', 23);
  4900. /**
  4901.  * Error code when an empty package name validate regex is passed in
  4902.  */
  4903. define('PEAR_CHANNELFILE_ERROR_EMPTY_REGEX', 24);
  4904. /**
  4905.  * Error code when a <function> tag has no version
  4906.  */
  4907. define('PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION', 25);
  4908. /**
  4909.  * Error code when a <function> tag has no name
  4910.  */
  4911. define('PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME', 26);
  4912. /**
  4913.  * Error code when a <validatepackage> tag has no name
  4914.  */
  4915. define('PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME', 27);
  4916. /**
  4917.  * Error code when a <validatepackage> tag has no version attribute
  4918.  */
  4919. define('PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION', 28);
  4920. /**
  4921.  * Error code when a mirror does not exist but is called for in one of the set*
  4922.  * methods.
  4923.  */
  4924. define('PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND', 32);
  4925. /**
  4926.  * Error code when a server port is not numeric
  4927.  */
  4928. define('PEAR_CHANNELFILE_ERROR_INVALID_PORT', 33);
  4929. /**
  4930.  * Error code when <static> contains no version attribute
  4931.  */
  4932. define('PEAR_CHANNELFILE_ERROR_NO_STATICVERSION', 34);
  4933. /**
  4934.  * Error code when <baseurl> contains no type attribute in a <rest> protocol definition
  4935.  */
  4936. define('PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE', 35);
  4937. /** 
  4938.  * Error code when a mirror is defined and the channel.xml represents the __uri pseudo-channel
  4939.  */
  4940. define('PEAR_CHANNELFILE_URI_CANT_MIRROR', 36);
  4941. /** 
  4942.  * Error code when ssl attribute is present and is not "yes"
  4943.  */
  4944. define('PEAR_CHANNELFILE_ERROR_INVALID_SSL', 37);
  4945. /**#@-*/
  4946.  
  4947. /**
  4948.  * Mirror types allowed.  Currently only internet servers are recognized.
  4949.  */
  4950. $GLOBALS['_PEAR_CHANNELS_MIRROR_TYPES'] =  array('server');
  4951.  
  4952.  
  4953. /**
  4954.  * The Channel handling class
  4955.  *
  4956.  * @category   pear
  4957.  * @package    PEAR
  4958.  * @author     Greg Beaver <cellog@php.net>
  4959.  * @copyright  1997-2008 The PHP Group
  4960.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  4961.  * @version    Release: 1.7.1
  4962.  * @link       http://pear.php.net/package/PEAR
  4963.  * @since      Class available since Release 1.4.0a1
  4964.  */
  4965. class PEAR_ChannelFile {
  4966.     /**
  4967.      * @access private
  4968.      * @var PEAR_ErrorStack
  4969.      * @access private
  4970.      */
  4971.     var $_stack;
  4972.     
  4973.     /**
  4974.      * Supported channel.xml versions, for parsing
  4975.      * @var array
  4976.      * @access private
  4977.      */
  4978.     var $_supportedVersions = array('1.0');
  4979.  
  4980.     /**
  4981.      * Parsed channel information
  4982.      * @var array
  4983.      * @access private
  4984.      */
  4985.     var $_channelInfo;
  4986.  
  4987.     /**
  4988.      * index into the subchannels array, used for parsing xml
  4989.      * @var int
  4990.      * @access private
  4991.      */
  4992.     var $_subchannelIndex;
  4993.  
  4994.     /**
  4995.      * index into the mirrors array, used for parsing xml
  4996.      * @var int
  4997.      * @access private
  4998.      */
  4999.     var $_mirrorIndex;
  5000.     
  5001.     /**
  5002.      * Flag used to determine the validity of parsed content
  5003.      * @var boolean
  5004.      * @access private
  5005.      */
  5006.     var $_isValid = false;
  5007.  
  5008.     function PEAR_ChannelFile()
  5009.     {
  5010.         $this->_stack = &new PEAR_ErrorStack('PEAR_ChannelFile');
  5011.         $this->_stack->setErrorMessageTemplate($this->_getErrorMessage());
  5012.         $this->_isValid = false;
  5013.     }
  5014.     
  5015.     /**
  5016.      * @return array
  5017.      * @access protected
  5018.      */
  5019.     function _getErrorMessage()
  5020.     {
  5021.         return
  5022.             array(
  5023.                 PEAR_CHANNELFILE_ERROR_INVALID_VERSION =>
  5024.                     'While parsing channel.xml, an invalid version number "%version% was passed in, expecting one of %versions%',
  5025.                 PEAR_CHANNELFILE_ERROR_NO_VERSION =>
  5026.                     'No version number found in <channel> tag',
  5027.                 PEAR_CHANNELFILE_ERROR_NO_XML_EXT =>
  5028.                     '%error%',
  5029.                 PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER =>
  5030.                     'Unable to create XML parser',
  5031.                 PEAR_CHANNELFILE_ERROR_PARSER_ERROR =>
  5032.                     '%error%',
  5033.                 PEAR_CHANNELFILE_ERROR_NO_NAME =>
  5034.                     'Missing channel name',
  5035.                 PEAR_CHANNELFILE_ERROR_INVALID_NAME =>
  5036.                     'Invalid channel %tag% "%name%"',
  5037.                 PEAR_CHANNELFILE_ERROR_NO_SUMMARY =>
  5038.                     'Missing channel summary',
  5039.                 PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY =>
  5040.                     'Channel summary should be on one line, but is multi-line',
  5041.                 PEAR_CHANNELFILE_ERROR_NO_HOST =>
  5042.                     'Missing channel server for %type% server',
  5043.                 PEAR_CHANNELFILE_ERROR_INVALID_HOST =>
  5044.                     'Server name "%server%" is invalid for %type% server',
  5045.                 PEAR_CHANNELFILE_ERROR_INVALID_MIRROR =>
  5046.                     'Invalid mirror name "%name%", mirror type %type%',
  5047.                 PEAR_CHANNELFILE_ERROR_INVALID_MIRRORTYPE =>
  5048.                     'Invalid mirror type "%type%"',
  5049.                 PEAR_CHANNELFILE_ERROR_INVALID =>
  5050.                     'Cannot generate xml, contents are invalid',
  5051.                 PEAR_CHANNELFILE_ERROR_EMPTY_REGEX =>
  5052.                     'packagenameregex cannot be empty',
  5053.                 PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION =>
  5054.                     '%parent% %protocol% function has no version',
  5055.                 PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME =>
  5056.                     '%parent% %protocol% function has no name',
  5057.                 PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE =>
  5058.                     '%parent% rest baseurl has no type',
  5059.                 PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME =>
  5060.                     'Validation package has no name in <validatepackage> tag',
  5061.                 PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION =>
  5062.                     'Validation package "%package%" has no version',
  5063.                 PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND =>
  5064.                     'Mirror "%mirror%" does not exist',
  5065.                 PEAR_CHANNELFILE_ERROR_INVALID_PORT =>
  5066.                     'Port "%port%" must be numeric',
  5067.                 PEAR_CHANNELFILE_ERROR_NO_STATICVERSION =>
  5068.                     '<static> tag must contain version attribute',
  5069.                 PEAR_CHANNELFILE_URI_CANT_MIRROR =>
  5070.                     'The __uri pseudo-channel cannot have mirrors',
  5071.                 PEAR_CHANNELFILE_ERROR_INVALID_SSL =>
  5072.                     '%server% has invalid ssl attribute "%ssl%" can only be yes or not present',
  5073.             );
  5074.     }
  5075.  
  5076.     /**
  5077.      * @param string contents of package.xml file
  5078.      * @return bool success of parsing
  5079.      */
  5080.     function fromXmlString($data)
  5081.     {
  5082.         if (preg_match('/<channel\s+version="([0-9]+\.[0-9]+)"/', $data, $channelversion)) {
  5083.             if (!in_array($channelversion[1], $this->_supportedVersions)) {
  5084.                 $this->_stack->push(PEAR_CHANNELFILE_ERROR_INVALID_VERSION, 'error',
  5085.                     array('version' => $channelversion[1]));
  5086.                 return false;
  5087.             }
  5088.             $parser = new PEAR_XMLParser;
  5089.             $result = $parser->parse($data);
  5090.             if ($result !== true) {
  5091.                 if ($result->getCode() == 1) {
  5092.                     $this->_stack->push(PEAR_CHANNELFILE_ERROR_NO_XML_EXT, 'error',
  5093.                         array('error' => $result->getMessage()));
  5094.                 } else {
  5095.                     $this->_stack->push(PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER, 'error');
  5096.                 }
  5097.                 return false;
  5098.             }
  5099.             $this->_channelInfo = $parser->getData();
  5100.             return true;
  5101.         } else {
  5102.             $this->_stack->push(PEAR_CHANNELFILE_ERROR_NO_VERSION, 'error', array('xml' => $data));
  5103.             return false;
  5104.         }
  5105.     }
  5106.     
  5107.     /**
  5108.      * @return array
  5109.      */
  5110.     function toArray()
  5111.     {
  5112.         if (!$this->_isValid && !$this->validate()) {
  5113.             return false;
  5114.         }
  5115.         return $this->_channelInfo;
  5116.     }
  5117.     
  5118.     /**
  5119.      * @param array
  5120.      * @static
  5121.      * @return PEAR_ChannelFile|false false if invalid
  5122.      */
  5123.     function &fromArray($data, $compatibility = false, $stackClass = 'PEAR_ErrorStack')
  5124.     {
  5125.         $a = new PEAR_ChannelFile($compatibility, $stackClass);
  5126.         $a->_fromArray($data);
  5127.         if (!$a->validate()) {
  5128.             $a = false;
  5129.             return $a;
  5130.         }
  5131.         return $a;
  5132.     }
  5133.  
  5134.     /**
  5135.      * Unlike {@link fromArray()} this does not do any validation
  5136.      * @param array
  5137.      * @static
  5138.      * @return PEAR_ChannelFile
  5139.      */
  5140.     function &fromArrayWithErrors($data, $compatibility = false,
  5141.                                   $stackClass = 'PEAR_ErrorStack')
  5142.     {
  5143.         $a = new PEAR_ChannelFile($compatibility, $stackClass);
  5144.         $a->_fromArray($data);
  5145.         return $a;
  5146.     }
  5147.     
  5148.     /**
  5149.      * @param array
  5150.      * @access private
  5151.      */
  5152.     function _fromArray($data)
  5153.     {
  5154.         $this->_channelInfo = $data;
  5155.     }
  5156.     
  5157.     /**
  5158.      * Wrapper to {@link PEAR_ErrorStack::getErrors()}
  5159.      * @param boolean determines whether to purge the error stack after retrieving
  5160.      * @return array
  5161.      */
  5162.     function getErrors($purge = false)
  5163.     {
  5164.         return $this->_stack->getErrors($purge);
  5165.     }
  5166.  
  5167.     /**
  5168.      * Unindent given string (?)
  5169.      *
  5170.      * @param string $str The string that has to be unindented.
  5171.      * @return string
  5172.      * @access private
  5173.      */
  5174.     function _unIndent($str)
  5175.     {
  5176.         // remove leading newlines
  5177.         $str = preg_replace('/^[\r\n]+/', '', $str);
  5178.         // find whitespace at the beginning of the first line
  5179.         $indent_len = strspn($str, " \t");
  5180.         $indent = substr($str, 0, $indent_len);
  5181.         $data = '';
  5182.         // remove the same amount of whitespace from following lines
  5183.         foreach (explode("\n", $str) as $line) {
  5184.             if (substr($line, 0, $indent_len) == $indent) {
  5185.                 $data .= substr($line, $indent_len) . "\n";
  5186.             }
  5187.         }
  5188.         return $data;
  5189.     }
  5190.  
  5191.     /**
  5192.      * Parse a channel.xml file.  Expects the name of
  5193.      * a channel xml file as input.
  5194.      *
  5195.      * @param string  $descfile  name of channel xml file
  5196.      * @return bool success of parsing
  5197.      */
  5198.     function fromXmlFile($descfile)
  5199.     {
  5200.         if (!file_exists($descfile) || !is_file($descfile) || !is_readable($descfile) ||
  5201.              (!$fp = fopen($descfile, 'r'))) {
  5202.             require_once 'phar://go-pear.phar/' . 'PEAR.php';
  5203.             return PEAR::raiseError("Unable to open $descfile");
  5204.         }
  5205.  
  5206.         // read the whole thing so we only get one cdata callback
  5207.         // for each block of cdata
  5208.         fclose($fp);
  5209.         $data = file_get_contents($descfile);
  5210.         return $this->fromXmlString($data);
  5211.     }
  5212.  
  5213.     /**
  5214.      * Parse channel information from different sources
  5215.      *
  5216.      * This method is able to extract information about a channel
  5217.      * from an .xml file or a string
  5218.      *
  5219.      * @access public
  5220.      * @param  string Filename of the source or the source itself
  5221.      * @return bool
  5222.      */
  5223.     function fromAny($info)
  5224.     {
  5225.         if (is_string($info) && file_exists($info) && strlen($info) < 255) {
  5226.             $tmp = substr($info, -4);
  5227.             if ($tmp == '.xml') {
  5228.                 $info = $this->fromXmlFile($info);
  5229.             } else {
  5230.                 $fp = fopen($info, "r");
  5231.                 $test = fread($fp, 5);
  5232.                 fclose($fp);
  5233.                 if ($test == "<?xml") {
  5234.                     $info = $this->fromXmlFile($info);
  5235.                 }
  5236.             }
  5237.             if (PEAR::isError($info)) {
  5238.                 require_once 'phar://go-pear.phar/' . 'PEAR.php';
  5239.                 return PEAR::raiseError($info);
  5240.             }
  5241.         }
  5242.         if (is_string($info)) {
  5243.             $info = $this->fromXmlString($info);
  5244.         }
  5245.         return $info;
  5246.     }
  5247.  
  5248.     /**
  5249.      * Return an XML document based on previous parsing and modifications
  5250.      *
  5251.      * @return string XML data
  5252.      *
  5253.      * @access public
  5254.      */
  5255.     function toXml()
  5256.     {
  5257.         if (!$this->_isValid && !$this->validate()) {
  5258.             $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID);
  5259.             return false;
  5260.         }
  5261.         if (!isset($this->_channelInfo['attribs']['version'])) {
  5262.             $this->_channelInfo['attribs']['version'] = '1.0';
  5263.         }
  5264.         $channelInfo = $this->_channelInfo;
  5265.         $ret = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n";
  5266.         $ret .= "<channel version=\"" .
  5267.             $channelInfo['attribs']['version'] . "\" xmlns=\"http://pear.php.net/channel-1.0\"
  5268.   xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
  5269.   xsi:schemaLocation=\"http://pear.php.net/dtd/channel-"
  5270.             . $channelInfo['attribs']['version'] . " http://pear.php.net/dtd/channel-" .
  5271.             $channelInfo['attribs']['version'] . ".xsd\">
  5272.  <name>$channelInfo[name]</name>
  5273.  <summary>" . htmlspecialchars($channelInfo['summary'])."</summary>
  5274. ";
  5275.         if (isset($channelInfo['suggestedalias'])) {
  5276.             $ret .= ' <suggestedalias>' . $channelInfo['suggestedalias'] . "</suggestedalias>\n";
  5277.         }
  5278.         if (isset($channelInfo['validatepackage'])) {
  5279.             $ret .= ' <validatepackage version="' .
  5280.                 $channelInfo['validatepackage']['attribs']['version']. '">' .
  5281.                 htmlspecialchars($channelInfo['validatepackage']['_content']) .
  5282.                 "</validatepackage>\n";
  5283.         }
  5284.         $ret .= " <servers>\n";
  5285.         $ret .= '  <primary';
  5286.         if (isset($channelInfo['servers']['primary']['attribs']['ssl'])) {
  5287.             $ret .= ' ssl="' . $channelInfo['servers']['primary']['attribs']['ssl'] . '"';
  5288.         }
  5289.         if (isset($channelInfo['servers']['primary']['attribs']['port'])) {
  5290.             $ret .= ' port="' . $channelInfo['servers']['primary']['attribs']['port'] . '"';
  5291.         }
  5292.         $ret .= ">\n";
  5293.         if (isset($channelInfo['servers']['primary']['xmlrpc'])) {
  5294.             $ret .= $this->_makeXmlrpcXml($channelInfo['servers']['primary']['xmlrpc'], '   ');
  5295.         }
  5296.         if (isset($channelInfo['servers']['primary']['rest'])) {
  5297.             $ret .= $this->_makeRestXml($channelInfo['servers']['primary']['rest'], '   ');
  5298.         }
  5299.         if (isset($channelInfo['servers']['primary']['soap'])) {
  5300.             $ret .= $this->_makeSoapXml($channelInfo['servers']['primary']['soap'], '   ');
  5301.         }
  5302.         $ret .= "  </primary>\n";
  5303.         if (isset($channelInfo['servers']['mirror'])) {
  5304.             $ret .= $this->_makeMirrorsXml($channelInfo);
  5305.         }
  5306.         $ret .= " </servers>\n";
  5307.         $ret .= "</channel>";
  5308.         return str_replace("\r", "\n", str_replace("\r\n", "\n", $ret));
  5309.     }
  5310.  
  5311.     /**
  5312.      * Generate the <xmlrpc> tag
  5313.      * @access private
  5314.      */
  5315.     function _makeXmlrpcXml($info, $indent)
  5316.     {
  5317.         $ret = $indent . "<xmlrpc";
  5318.         if (isset($info['attribs']['path'])) {
  5319.             $ret .= ' path="' . htmlspecialchars($info['attribs']['path']) . '"';
  5320.         }
  5321.         $ret .= ">\n";
  5322.         $ret .= $this->_makeFunctionsXml($info['function'], "$indent ");
  5323.         $ret .= $indent . "</xmlrpc>\n";
  5324.         return $ret;
  5325.     }
  5326.  
  5327.     /**
  5328.      * Generate the <soap> tag
  5329.      * @access private
  5330.      */
  5331.     function _makeSoapXml($info, $indent)
  5332.     {
  5333.         $ret = $indent . "<soap";
  5334.         if (isset($info['attribs']['path'])) {
  5335.             $ret .= ' path="' . htmlspecialchars($info['attribs']['path']) . '"';
  5336.         }
  5337.         $ret .= ">\n";
  5338.         $ret .= $this->_makeFunctionsXml($info['function'], "$indent ");
  5339.         $ret .= $indent . "</soap>\n";
  5340.         return $ret;
  5341.     }
  5342.  
  5343.     /**
  5344.      * Generate the <rest> tag
  5345.      * @access private
  5346.      */
  5347.     function _makeRestXml($info, $indent)
  5348.     {
  5349.         $ret = $indent . "<rest>\n";
  5350.         if (!isset($info['baseurl'][0])) {
  5351.             $info['baseurl'] = array($info['baseurl']);
  5352.         }
  5353.         foreach ($info['baseurl'] as $url) {
  5354.             $ret .= "$indent <baseurl type=\"" . $url['attribs']['type'] . "\"";
  5355.             $ret .= ">" . $url['_content'] . "</baseurl>\n";
  5356.         }
  5357.         $ret .= $indent . "</rest>\n";
  5358.         return $ret;
  5359.     }
  5360.  
  5361.     /**
  5362.      * Generate the <mirrors> tag
  5363.      * @access private
  5364.      */
  5365.     function _makeMirrorsXml($channelInfo)
  5366.     {
  5367.         $ret = "";
  5368.         if (!isset($channelInfo['servers']['mirror'][0])) {
  5369.             $channelInfo['servers']['mirror'] = array($channelInfo['servers']['mirror']);
  5370.         }
  5371.         foreach ($channelInfo['servers']['mirror'] as $mirror) {
  5372.             $ret .= '  <mirror host="' . $mirror['attribs']['host'] . '"';
  5373.             if (isset($mirror['attribs']['port'])) {
  5374.                 $ret .= ' port="' . $mirror['attribs']['port'] . '"';
  5375.             }
  5376.             if (isset($mirror['attribs']['ssl'])) {
  5377.                 $ret .= ' ssl="' . $mirror['attribs']['ssl'] . '"';
  5378.             }
  5379.             $ret .= ">\n";
  5380.             if (isset($mirror['xmlrpc']) || isset($mirror['soap'])) {
  5381.                 if (isset($mirror['xmlrpc'])) {
  5382.                     $ret .= $this->_makeXmlrpcXml($mirror['xmlrpc'], '   ');
  5383.                 }
  5384.                 if (isset($mirror['rest'])) {
  5385.                     $ret .= $this->_makeRestXml($mirror['rest'], '   ');
  5386.                 }
  5387.                 if (isset($mirror['soap'])) {
  5388.                     $ret .= $this->_makeSoapXml($mirror['soap'], '   ');
  5389.                 }
  5390.                 $ret .= "  </mirror>\n";
  5391.             } else {
  5392.                 $ret .= "/>\n";
  5393.             }
  5394.         }
  5395.         return $ret;
  5396.     }
  5397.  
  5398.     /**
  5399.      * Generate the <functions> tag
  5400.      * @access private
  5401.      */
  5402.     function _makeFunctionsXml($functions, $indent, $rest = false)
  5403.     {
  5404.         $ret = '';
  5405.         if (!isset($functions[0])) {
  5406.             $functions = array($functions);
  5407.         }
  5408.         foreach ($functions as $function) {
  5409.             $ret .= "$indent<function version=\"" . $function['attribs']['version'] . "\"";
  5410.             if ($rest) {
  5411.                 $ret .= ' uri="' . $function['attribs']['uri'] . '"';
  5412.             }
  5413.             $ret .= ">" . $function['_content'] . "</function>\n";
  5414.         }
  5415.         return $ret;
  5416.     }
  5417.  
  5418.     /**
  5419.      * Validation error.  Also marks the object contents as invalid
  5420.      * @param error code
  5421.      * @param array error information
  5422.      * @access private
  5423.      */
  5424.     function _validateError($code, $params = array())
  5425.     {
  5426.         $this->_stack->push($code, 'error', $params);
  5427.         $this->_isValid = false;
  5428.     }
  5429.  
  5430.     /**
  5431.      * Validation warning.  Does not mark the object contents invalid.
  5432.      * @param error code
  5433.      * @param array error information
  5434.      * @access private
  5435.      */
  5436.     function _validateWarning($code, $params = array())
  5437.     {
  5438.         $this->_stack->push($code, 'warning', $params);
  5439.     }
  5440.  
  5441.     /**
  5442.      * Validate parsed file.
  5443.      *
  5444.      * @access public
  5445.      * @return boolean
  5446.      */
  5447.     function validate()
  5448.     {
  5449.         $this->_isValid = true;
  5450.         $info = $this->_channelInfo;
  5451.         if (empty($info['name'])) {
  5452.             $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_NAME);
  5453.         } elseif (!$this->validChannelServer($info['name'])) {
  5454.             if ($info['name'] != '__uri') {
  5455.                 $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, array('tag' => 'name',
  5456.                     'name' => $info['name']));
  5457.             }
  5458.         }
  5459.         if (empty($info['summary'])) {
  5460.             $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SUMMARY);
  5461.         } elseif (strpos(trim($info['summary']), "\n") !== false) {
  5462.             $this->_validateWarning(PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY,
  5463.                 array('summary' => $info['summary']));
  5464.         }
  5465.         if (isset($info['suggestedalias'])) {
  5466.             if (!$this->validChannelServer($info['suggestedalias'])) {
  5467.                 $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
  5468.                     array('tag' => 'suggestedalias', 'name' =>$info['suggestedalias']));
  5469.             }
  5470.         }
  5471.         if (isset($info['localalias'])) {
  5472.             if (!$this->validChannelServer($info['localalias'])) {
  5473.                 $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
  5474.                     array('tag' => 'localalias', 'name' =>$info['localalias']));
  5475.             }
  5476.         }
  5477.         if (isset($info['validatepackage'])) {
  5478.             if (!isset($info['validatepackage']['_content'])) {
  5479.                 $this->_validateError(PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME);
  5480.             }
  5481.             if (!isset($info['validatepackage']['attribs']['version'])) {
  5482.                 $content = isset($info['validatepackage']['_content']) ?
  5483.                     $info['validatepackage']['_content'] :
  5484.                     null;
  5485.                 $this->_validateError(PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION,
  5486.                     array('package' => $content));
  5487.             }
  5488.         }
  5489.         if (isset($info['servers']['primary']['attribs']['port']) &&
  5490.               !is_numeric($info['servers']['primary']['attribs']['port'])) {
  5491.             $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_PORT,
  5492.                 array('port' => $info['servers']['primary']['attribs']['port']));
  5493.         }
  5494.         if (isset($info['servers']['primary']['attribs']['ssl']) &&
  5495.               $info['servers']['primary']['attribs']['ssl'] != 'yes') {
  5496.             $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_SSL,
  5497.                 array('ssl' => $info['servers']['primary']['attribs']['ssl'],
  5498.                     'server' => $info['name']));
  5499.         }
  5500.  
  5501.         if (isset($info['servers']['primary']['xmlrpc']) &&
  5502.               isset($info['servers']['primary']['xmlrpc']['function'])) {
  5503.             $this->_validateFunctions('xmlrpc', $info['servers']['primary']['xmlrpc']['function']);
  5504.         }
  5505.         if (isset($info['servers']['primary']['soap']) &&
  5506.               isset($info['servers']['primary']['soap']['function'])) {
  5507.             $this->_validateFunctions('soap', $info['servers']['primary']['soap']['function']);
  5508.         }
  5509.         if (isset($info['servers']['primary']['rest']) &&
  5510.               isset($info['servers']['primary']['rest']['baseurl'])) {
  5511.             $this->_validateFunctions('rest', $info['servers']['primary']['rest']['baseurl']);
  5512.         }
  5513.         if (isset($info['servers']['mirror'])) {
  5514.             if ($this->_channelInfo['name'] == '__uri') {
  5515.                 $this->_validateError(PEAR_CHANNELFILE_URI_CANT_MIRROR);
  5516.             }
  5517.             if (!isset($info['servers']['mirror'][0])) {
  5518.                 $info['servers']['mirror'] = array($info['servers']['mirror']);
  5519.             }
  5520.             foreach ($info['servers']['mirror'] as $mirror) {
  5521.                 if (!isset($mirror['attribs']['host'])) {
  5522.                     $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_HOST,
  5523.                       array('type' => 'mirror'));
  5524.                 } elseif (!$this->validChannelServer($mirror['attribs']['host'])) {
  5525.                     $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_HOST,
  5526.                         array('server' => $mirror['attribs']['host'], 'type' => 'mirror'));
  5527.                 }
  5528.                 if (isset($mirror['attribs']['ssl']) && $mirror['attribs']['ssl'] != 'yes') {
  5529.                     $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_SSL,
  5530.                         array('ssl' => $info['ssl'], 'server' => $mirror['attribs']['host']));
  5531.                 }
  5532.                 if (isset($mirror['xmlrpc'])) {
  5533.                     $this->_validateFunctions('xmlrpc',
  5534.                         $mirror['xmlrpc']['function'], $mirror['attribs']['host']);
  5535.                 }
  5536.                 if (isset($mirror['soap'])) {
  5537.                     $this->_validateFunctions('soap', $mirror['soap']['function'],
  5538.                         $mirror['attribs']['host']);
  5539.                 }
  5540.                 if (isset($mirror['rest'])) {
  5541.                     $this->_validateFunctions('rest', $mirror['rest']['baseurl'],
  5542.                         $mirror['attribs']['host']);
  5543.                 }
  5544.             }
  5545.         }
  5546.         return $this->_isValid;
  5547.     }
  5548.  
  5549.     /**
  5550.      * @param string xmlrpc or soap - protocol name this function applies to
  5551.      * @param array the functions
  5552.      * @param string the name of the parent element (mirror name, for instance)
  5553.      */
  5554.     function _validateFunctions($protocol, $functions, $parent = '')
  5555.     {
  5556.         if (!isset($functions[0])) {
  5557.             $functions = array($functions);
  5558.         }
  5559.         foreach ($functions as $function) {
  5560.             if (!isset($function['_content']) || empty($function['_content'])) {
  5561.                 $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME,
  5562.                     array('parent' => $parent, 'protocol' => $protocol));
  5563.             }
  5564.             if ($protocol == 'rest') {
  5565.                 if (!isset($function['attribs']['type']) ||
  5566.                       empty($function['attribs']['type'])) {
  5567.                     $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_BASEURLTYPE,
  5568.                         array('parent' => $parent, 'protocol' => $protocol));
  5569.                 }
  5570.             } else {
  5571.                 if (!isset($function['attribs']['version']) ||
  5572.                       empty($function['attribs']['version'])) {
  5573.                     $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION,
  5574.                         array('parent' => $parent, 'protocol' => $protocol));
  5575.                 }
  5576.             }
  5577.         }
  5578.     }
  5579.  
  5580.     /**
  5581.      * Test whether a string contains a valid channel server.
  5582.      * @param string $ver the package version to test
  5583.      * @return bool
  5584.      */
  5585.     function validChannelServer($server)
  5586.     {
  5587.         if ($server == '__uri') {
  5588.             return true;
  5589.         }
  5590.         return (bool) preg_match(PEAR_CHANNELS_SERVER_PREG, $server);
  5591.     }
  5592.  
  5593.     /**
  5594.      * @return string|false
  5595.      */
  5596.     function getName()
  5597.     {
  5598.         if (isset($this->_channelInfo['name'])) {
  5599.             return $this->_channelInfo['name'];
  5600.         } else {
  5601.             return false;
  5602.         }
  5603.     }
  5604.  
  5605.     /**
  5606.      * @return string|false
  5607.      */
  5608.     function getServer()
  5609.     {
  5610.         if (isset($this->_channelInfo['name'])) {
  5611.             return $this->_channelInfo['name'];
  5612.         } else {
  5613.             return false;
  5614.         }
  5615.     }
  5616.  
  5617.     /**
  5618.      * @return int|80 port number to connect to
  5619.      */
  5620.     function getPort($mirror = false)
  5621.     {
  5622.         if ($mirror) {
  5623.             if ($mir = $this->getMirror($mirror)) {
  5624.                 if (isset($mir['attribs']['port'])) {
  5625.                     return $mir['attribs']['port'];
  5626.                 } else {
  5627.                     if ($this->getSSL($mirror)) {
  5628.                         return 443;
  5629.                     }
  5630.                     return 80;
  5631.                 }
  5632.             }
  5633.             return false;
  5634.         }
  5635.         if (isset($this->_channelInfo['servers']['primary']['attribs']['port'])) {
  5636.             return $this->_channelInfo['servers']['primary']['attribs']['port'];
  5637.         }
  5638.         if ($this->getSSL()) {
  5639.             return 443;
  5640.         }
  5641.         return 80;
  5642.     }
  5643.  
  5644.     /**
  5645.      * @return bool Determines whether secure sockets layer (SSL) is used to connect to this channel
  5646.      */
  5647.     function getSSL($mirror = false)
  5648.     {
  5649.         if ($mirror) {
  5650.             if ($mir = $this->getMirror($mirror)) {
  5651.                 if (isset($mir['attribs']['ssl'])) {
  5652.                     return true;
  5653.                 } else {
  5654.                     return false;
  5655.                 }
  5656.             }
  5657.             return false;
  5658.         }
  5659.         if (isset($this->_channelInfo['servers']['primary']['attribs']['ssl'])) {
  5660.             return true;
  5661.         }
  5662.         return false;
  5663.     }
  5664.  
  5665.     /**
  5666.      * @return string|false
  5667.      */
  5668.     function getSummary()
  5669.     {
  5670.         if (isset($this->_channelInfo['summary'])) {
  5671.             return $this->_channelInfo['summary'];
  5672.         } else {
  5673.             return false;
  5674.         }
  5675.     }
  5676.  
  5677.     /**
  5678.      * @param string xmlrpc or soap
  5679.      * @param string|false mirror name or false for primary server
  5680.      */
  5681.     function getPath($protocol, $mirror = false)
  5682.     {   
  5683.         if (!in_array($protocol, array('xmlrpc', 'soap'))) {
  5684.             return false;
  5685.         }
  5686.         if ($mirror) {
  5687.             if (!($mir = $this->getMirror($mirror))) {
  5688.                 return false;
  5689.             }
  5690.             if (isset($mir[$protocol]['attribs']['path'])) {
  5691.                 return $mir[$protocol]['attribs']['path'];
  5692.             } else {
  5693.                 return $protocol . '.php';
  5694.             }
  5695.         } elseif (isset($this->_channelInfo['servers']['primary'][$protocol]['attribs']['path'])) {
  5696.             return $this->_channelInfo['servers']['primary'][$protocol]['attribs']['path'];
  5697.         }
  5698.         return $protocol . '.php';
  5699.     }
  5700.  
  5701.     /**
  5702.      * @param string protocol type (xmlrpc, soap)
  5703.      * @param string Mirror name
  5704.      * @return array|false
  5705.      */
  5706.     function getFunctions($protocol, $mirror = false)
  5707.     {
  5708.         if ($this->getName() == '__uri') {
  5709.             return false;
  5710.         }
  5711.         if ($protocol == 'rest') {
  5712.             $function = 'baseurl';
  5713.         } else {
  5714.             $function = 'function';
  5715.         }
  5716.         if ($mirror) {
  5717.             if ($mir = $this->getMirror($mirror)) {
  5718.                 if (isset($mir[$protocol][$function])) {
  5719.                     return $mir[$protocol][$function];
  5720.                 }
  5721.             }
  5722.             return false;
  5723.         }
  5724.         if (isset($this->_channelInfo['servers']['primary'][$protocol][$function])) {
  5725.             return $this->_channelInfo['servers']['primary'][$protocol][$function];
  5726.         } else {
  5727.             return false;
  5728.         }
  5729.     }
  5730.  
  5731.     /**
  5732.      * @param string Protocol type
  5733.      * @param string Function name (null to return the
  5734.      *               first protocol of the type requested)
  5735.      * @param string Mirror name, if any
  5736.      * @return array
  5737.      */
  5738.      function getFunction($type, $name = null, $mirror = false)
  5739.      {
  5740.         $protocols = $this->getFunctions($type, $mirror);
  5741.         if (!$protocols) {
  5742.             return false;
  5743.         }
  5744.         foreach ($protocols as $protocol) {
  5745.             if ($name === null) {
  5746.                 return $protocol;
  5747.             }
  5748.             if ($protocol['_content'] != $name) {
  5749.                 continue;
  5750.             }
  5751.             return $protocol;
  5752.         }
  5753.         return false;
  5754.      }
  5755.  
  5756.     /**
  5757.      * @param string protocol type
  5758.      * @param string protocol name
  5759.      * @param string version
  5760.      * @param string mirror name
  5761.      * @return boolean
  5762.      */
  5763.     function supports($type, $name = null, $mirror = false, $version = '1.0')
  5764.     {
  5765.         $protocols = $this->getFunctions($type, $mirror);
  5766.         if (!$protocols) {
  5767.             return false;
  5768.         }
  5769.         foreach ($protocols as $protocol) {
  5770.             if ($protocol['attribs']['version'] != $version) {
  5771.                 continue;
  5772.             }
  5773.             if ($name === null) {
  5774.                 return true;
  5775.             }
  5776.             if ($protocol['_content'] != $name) {
  5777.                 continue;
  5778.             }
  5779.             return true;
  5780.         }
  5781.         return false;
  5782.     }
  5783.  
  5784.     /**
  5785.      * Determines whether a channel supports Representational State Transfer (REST) protocols
  5786.      * for retrieving channel information
  5787.      * @param string
  5788.      * @return bool
  5789.      */
  5790.     function supportsREST($mirror = false)
  5791.     {
  5792.         if ($mirror == $this->_channelInfo['name']) {
  5793.             $mirror = false;
  5794.         }
  5795.         if ($mirror) {
  5796.             if ($mir = $this->getMirror($mirror)) {
  5797.                 return isset($mir['rest']);
  5798.             }
  5799.             return false;
  5800.         }
  5801.         return isset($this->_channelInfo['servers']['primary']['rest']);
  5802.     }
  5803.  
  5804.     /**
  5805.      * Get the URL to access a base resource.
  5806.      *
  5807.      * Hyperlinks in the returned xml will be used to retrieve the proper information
  5808.      * needed.  This allows extreme extensibility and flexibility in implementation
  5809.      * @param string Resource Type to retrieve
  5810.      */
  5811.     function getBaseURL($resourceType, $mirror = false)
  5812.     {
  5813.         if ($mirror == $this->_channelInfo['name']) {
  5814.             $mirror = false;
  5815.         }
  5816.         if ($mirror) {
  5817.             if ($mir = $this->getMirror($mirror)) {
  5818.                 $rest = $mir['rest'];
  5819.             } else {
  5820.                 return false;
  5821.             }
  5822.         } else {
  5823.             $rest = $this->_channelInfo['servers']['primary']['rest'];
  5824.         }
  5825.         if (!isset($rest['baseurl'][0])) {
  5826.             $rest['baseurl'] = array($rest['baseurl']);
  5827.         }
  5828.         foreach ($rest['baseurl'] as $baseurl) {
  5829.             if (strtolower($baseurl['attribs']['type']) == strtolower($resourceType)) {
  5830.                 return $baseurl['_content'];
  5831.             }
  5832.         }
  5833.         return false;
  5834.     }
  5835.  
  5836.     /**
  5837.      * Since REST does not implement RPC, provide this as a logical wrapper around
  5838.      * resetFunctions for REST
  5839.      * @param string|false mirror name, if any
  5840.      */
  5841.     function resetREST($mirror = false)
  5842.     {
  5843.         return $this->resetFunctions('rest', $mirror);
  5844.     }
  5845.  
  5846.     /**
  5847.      * Empty all protocol definitions
  5848.      * @param string protocol type (xmlrpc, soap)
  5849.      * @param string|false mirror name, if any
  5850.      */
  5851.     function resetFunctions($type, $mirror = false)
  5852.     {
  5853.         if ($mirror) {
  5854.             if (isset($this->_channelInfo['servers']['mirror'])) {
  5855.                 $mirrors = $this->_channelInfo['servers']['mirror'];
  5856.                 if (!isset($mirrors[0])) {
  5857.                     $mirrors = array($mirrors);
  5858.                 }
  5859.                 foreach ($mirrors as $i => $mir) {
  5860.                     if ($mir['attribs']['host'] == $mirror) {
  5861.                         if (isset($this->_channelInfo['servers']['mirror'][$i][$type])) {
  5862.                             unset($this->_channelInfo['servers']['mirror'][$i][$type]);
  5863.                         }
  5864.                         return true;
  5865.                     }
  5866.                 }
  5867.                 return false;
  5868.             } else {
  5869.                 return false;
  5870.             }
  5871.         } else {
  5872.             if (isset($this->_channelInfo['servers']['primary'][$type])) {
  5873.                 unset($this->_channelInfo['servers']['primary'][$type]);
  5874.             }
  5875.             return true;
  5876.         }
  5877.     }
  5878.  
  5879.     /**
  5880.      * Set a channel's protocols to the protocols supported by pearweb
  5881.      */
  5882.     function setDefaultPEARProtocols($version = '1.0', $mirror = false)
  5883.     {
  5884.         switch ($version) {
  5885.             case '1.0' :
  5886.                 $this->resetFunctions('xmlrpc', $mirror);
  5887.                 $this->resetFunctions('soap', $mirror);
  5888.                 $this->resetREST($mirror);
  5889.                 $this->addFunction('xmlrpc', '1.0', 'logintest', $mirror);
  5890.                 $this->addFunction('xmlrpc', '1.0', 'package.listLatestReleases', $mirror);
  5891.                 $this->addFunction('xmlrpc', '1.0', 'package.listAll', $mirror);
  5892.                 $this->addFunction('xmlrpc', '1.0', 'package.info', $mirror);
  5893.                 $this->addFunction('xmlrpc', '1.0', 'package.getDownloadURL', $mirror);
  5894.                 $this->addFunction('xmlrpc', '1.1', 'package.getDownloadURL', $mirror);
  5895.                 $this->addFunction('xmlrpc', '1.0', 'package.getDepDownloadURL', $mirror);
  5896.                 $this->addFunction('xmlrpc', '1.1', 'package.getDepDownloadURL', $mirror);
  5897.                 $this->addFunction('xmlrpc', '1.0', 'package.search', $mirror);
  5898.                 $this->addFunction('xmlrpc', '1.0', 'channel.listAll', $mirror);
  5899.                 return true;
  5900.             break;
  5901.             default :
  5902.                 return false;
  5903.             break;
  5904.         }
  5905.     }
  5906.     
  5907.     /**
  5908.      * @return array
  5909.      */
  5910.     function getMirrors()
  5911.     {
  5912.         if (isset($this->_channelInfo['servers']['mirror'])) {
  5913.             $mirrors = $this->_channelInfo['servers']['mirror'];
  5914.             if (!isset($mirrors[0])) {
  5915.                 $mirrors = array($mirrors);
  5916.             }
  5917.             return $mirrors;
  5918.         } else {
  5919.             return array();
  5920.         }
  5921.     }
  5922.  
  5923.     /**
  5924.      * Get the unserialized XML representing a mirror
  5925.      * @return array|false
  5926.      */
  5927.     function getMirror($server)
  5928.     {
  5929.         foreach ($this->getMirrors() as $mirror) {
  5930.             if ($mirror['attribs']['host'] == $server) {
  5931.                 return $mirror;
  5932.             }
  5933.         }
  5934.         return false;
  5935.     }
  5936.  
  5937.     /**
  5938.      * @param string
  5939.      * @return string|false
  5940.      * @error PEAR_CHANNELFILE_ERROR_NO_NAME
  5941.      * @error PEAR_CHANNELFILE_ERROR_INVALID_NAME
  5942.      */
  5943.     function setName($name)
  5944.     {
  5945.         return $this->setServer($name);
  5946.     }
  5947.  
  5948.     /**
  5949.      * Set the socket number (port) that is used to connect to this channel
  5950.      * @param integer
  5951.      * @param string|false name of the mirror server, or false for the primary
  5952.      */
  5953.     function setPort($port, $mirror = false)
  5954.     {
  5955.         if ($mirror) {
  5956.             if (!isset($this->_channelInfo['servers']['mirror'])) {
  5957.                 $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
  5958.                     array('mirror' => $mirror));
  5959.                 return false;
  5960.             }
  5961.             if (isset($this->_channelInfo['servers']['mirror'][0])) {
  5962.                 foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
  5963.                     if ($mirror == $mir['attribs']['host']) {
  5964.                         $this->_channelInfo['servers']['mirror'][$i]['attribs']['port'] = $port;
  5965.                         return true;
  5966.                     }
  5967.                 }
  5968.                 return false;
  5969.             } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
  5970.                 $this->_channelInfo['servers']['mirror']['attribs']['port'] = $port;
  5971.                 $this->_isValid = false;
  5972.                 return true;
  5973.             }
  5974.         }
  5975.         $this->_channelInfo['servers']['primary']['attribs']['port'] = $port;
  5976.         $this->_isValid = false;
  5977.         return true;
  5978.     }
  5979.  
  5980.     /**
  5981.      * Set the socket number (port) that is used to connect to this channel
  5982.      * @param bool Determines whether to turn on SSL support or turn it off
  5983.      * @param string|false name of the mirror server, or false for the primary
  5984.      */
  5985.     function setSSL($ssl = true, $mirror = false)
  5986.     {
  5987.         if ($mirror) {
  5988.             if (!isset($this->_channelInfo['servers']['mirror'])) {
  5989.                 $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
  5990.                     array('mirror' => $mirror));
  5991.                 return false;
  5992.             }
  5993.             if (isset($this->_channelInfo['servers']['mirror'][0])) {
  5994.                 foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
  5995.                     if ($mirror == $mir['attribs']['host']) {
  5996.                         if (!$ssl) {
  5997.                             if (isset($this->_channelInfo['servers']['mirror'][$i]
  5998.                                   ['attribs']['ssl'])) {
  5999.                                 unset($this->_channelInfo['servers']['mirror'][$i]['attribs']['ssl']);
  6000.                             }
  6001.                         } else {
  6002.                             $this->_channelInfo['servers']['mirror'][$i]['attribs']['ssl'] = 'yes';
  6003.                         }
  6004.                         return true;
  6005.                     }
  6006.                 }
  6007.                 return false;
  6008.             } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
  6009.                 if (!$ssl) {
  6010.                     if (isset($this->_channelInfo['servers']['mirror']['attribs']['ssl'])) {
  6011.                         unset($this->_channelInfo['servers']['mirror']['attribs']['ssl']);
  6012.                     }
  6013.                 } else {
  6014.                     $this->_channelInfo['servers']['mirror']['attribs']['ssl'] = 'yes';
  6015.                 }
  6016.                 $this->_isValid = false;
  6017.                 return true;
  6018.             }
  6019.         }
  6020.         if ($ssl) {
  6021.             $this->_channelInfo['servers']['primary']['attribs']['ssl'] = 'yes';
  6022.         } else {
  6023.             if (isset($this->_channelInfo['servers']['primary']['attribs']['ssl'])) {
  6024.                 unset($this->_channelInfo['servers']['primary']['attribs']['ssl']);
  6025.             }
  6026.         }
  6027.         $this->_isValid = false;
  6028.         return true;
  6029.     }
  6030.  
  6031.     /**
  6032.      * Set the socket number (port) that is used to connect to this channel
  6033.      * @param integer
  6034.      * @param string|false name of the mirror server, or false for the primary
  6035.      */
  6036.     function setPath($protocol, $path, $mirror = false)
  6037.     {
  6038.         if (!in_array($protocol, array('xmlrpc', 'soap'))) {
  6039.             return false;
  6040.         }
  6041.         if ($mirror) {
  6042.             if (!isset($this->_channelInfo['servers']['mirror'])) {
  6043.                 $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
  6044.                     array('mirror' => $mirror));
  6045.                 return false;
  6046.             }
  6047.             if (isset($this->_channelInfo['servers']['mirror'][0])) {
  6048.                 foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
  6049.                     if ($mirror == $mir['attribs']['host']) {
  6050.                         $this->_channelInfo['servers']['mirror'][$i][$protocol]['attribs']['path'] =
  6051.                             $path;
  6052.                         return true;
  6053.                     }
  6054.                 }
  6055.                 $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
  6056.                     array('mirror' => $mirror));
  6057.                 return false;
  6058.             } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
  6059.                 $this->_channelInfo['servers']['mirror'][$protocol]['attribs']['path'] = $path;
  6060.                 $this->_isValid = false;
  6061.                 return true;
  6062.             }
  6063.         }
  6064.         $this->_channelInfo['servers']['primary'][$protocol]['attribs']['path'] = $path;
  6065.         $this->_isValid = false;
  6066.         return true;
  6067.     }
  6068.  
  6069.     /**
  6070.      * @param string
  6071.      * @return string|false
  6072.      * @error PEAR_CHANNELFILE_ERROR_NO_SERVER
  6073.      * @error PEAR_CHANNELFILE_ERROR_INVALID_SERVER
  6074.      */
  6075.     function setServer($server, $mirror = false)
  6076.     {
  6077.         if (empty($server)) {
  6078.             $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SERVER);
  6079.             return false;
  6080.         } elseif (!$this->validChannelServer($server)) {
  6081.             $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
  6082.                 array('tag' => 'name', 'name' => $server));
  6083.             return false;
  6084.         }
  6085.         if ($mirror) {
  6086.             $found = false;
  6087.             foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
  6088.                 if ($mirror == $mir['attribs']['host']) {
  6089.                     $found = true;
  6090.                     break;
  6091.                 }
  6092.             }
  6093.             if (!$found) {
  6094.                 $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
  6095.                     array('mirror' => $mirror));
  6096.                 return false;
  6097.             }
  6098.             $this->_channelInfo['mirror'][$i]['attribs']['host'] = $server;
  6099.             return true;
  6100.         }
  6101.         $this->_channelInfo['name'] = $server;
  6102.         return true;
  6103.     }
  6104.  
  6105.     /**
  6106.      * @param string
  6107.      * @return boolean success
  6108.      * @error PEAR_CHANNELFILE_ERROR_NO_SUMMARY
  6109.      * @warning PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY
  6110.      */
  6111.     function setSummary($summary)
  6112.     {
  6113.         if (empty($summary)) {
  6114.             $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SUMMARY);
  6115.             return false;
  6116.         } elseif (strpos(trim($summary), "\n") !== false) {
  6117.             $this->_validateWarning(PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY,
  6118.                 array('summary' => $summary));
  6119.         }
  6120.         $this->_channelInfo['summary'] = $summary;
  6121.         return true;
  6122.     }
  6123.  
  6124.     /**
  6125.      * @param string
  6126.      * @param boolean determines whether the alias is in channel.xml or local
  6127.      * @return boolean success
  6128.      */
  6129.     function setAlias($alias, $local = false)
  6130.     {
  6131.         if (!$this->validChannelServer($alias)) {
  6132.             $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
  6133.                 array('tag' => 'suggestedalias', 'name' => $alias));
  6134.             return false;
  6135.         }
  6136.         if ($local) {
  6137.             $this->_channelInfo['localalias'] = $alias;
  6138.         } else {
  6139.             $this->_channelInfo['suggestedalias'] = $alias;
  6140.         }
  6141.         return true;
  6142.     }
  6143.  
  6144.     /**
  6145.      * @return string
  6146.      */
  6147.     function getAlias()
  6148.     {
  6149.         if (isset($this->_channelInfo['localalias'])) {
  6150.             return $this->_channelInfo['localalias'];
  6151.         }
  6152.         if (isset($this->_channelInfo['suggestedalias'])) {
  6153.             return $this->_channelInfo['suggestedalias'];
  6154.         }
  6155.         if (isset($this->_channelInfo['name'])) {
  6156.             return $this->_channelInfo['name'];
  6157.         }
  6158.         return '';
  6159.     }
  6160.  
  6161.     /**
  6162.      * Set the package validation object if it differs from PEAR's default
  6163.      * The class must be includeable via changing _ in the classname to path separator,
  6164.      * but no checking of this is made.
  6165.      * @param string|false pass in false to reset to the default packagename regex
  6166.      * @return boolean success
  6167.      */
  6168.     function setValidationPackage($validateclass, $version)
  6169.     {
  6170.         if (empty($validateclass)) {
  6171.             unset($this->_channelInfo['validatepackage']);
  6172.         }
  6173.         $this->_channelInfo['validatepackage'] = array('_content' => $validateclass);
  6174.         $this->_channelInfo['validatepackage']['attribs'] = array('version' => $version);
  6175.     }
  6176.  
  6177.     /**
  6178.      * Add a protocol to the provides section
  6179.      * @param string protocol type
  6180.      * @param string protocol version
  6181.      * @param string protocol name, if any
  6182.      * @param string mirror name, if this is a mirror's protocol
  6183.      * @return bool
  6184.      */
  6185.     function addFunction($type, $version, $name = '', $mirror = false)
  6186.     {
  6187.         if ($mirror) {
  6188.             return $this->addMirrorFunction($mirror, $type, $version, $name);
  6189.         }
  6190.         $set = array('attribs' => array('version' => $version), '_content' => $name);
  6191.         if (!isset($this->_channelInfo['servers']['primary'][$type]['function'])) {
  6192.             if (!isset($this->_channelInfo['servers'])) {
  6193.                 $this->_channelInfo['servers'] = array('primary' =>
  6194.                     array($type => array()));
  6195.             } elseif (!isset($this->_channelInfo['servers']['primary'])) {
  6196.                 $this->_channelInfo['servers']['primary'] = array($type => array());
  6197.             }
  6198.             $this->_channelInfo['servers']['primary'][$type]['function'] = $set;
  6199.             $this->_isValid = false;
  6200.             return true;
  6201.         } elseif (!isset($this->_channelInfo['servers']['primary'][$type]['function'][0])) {
  6202.             $this->_channelInfo['servers']['primary'][$type]['function'] = array(
  6203.                 $this->_channelInfo['servers']['primary'][$type]['function']);
  6204.         }
  6205.         $this->_channelInfo['servers']['primary'][$type]['function'][] = $set;
  6206.         return true;
  6207.     }
  6208.     /**
  6209.      * Add a protocol to a mirror's provides section
  6210.      * @param string mirror name (server)
  6211.      * @param string protocol type
  6212.      * @param string protocol version
  6213.      * @param string protocol name, if any
  6214.      */
  6215.     function addMirrorFunction($mirror, $type, $version, $name = '')
  6216.     {
  6217.         if (!isset($this->_channelInfo['servers']['mirror'])) {
  6218.             $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
  6219.                 array('mirror' => $mirror));
  6220.             return false;
  6221.         }
  6222.         $setmirror = false;
  6223.         if (isset($this->_channelInfo['servers']['mirror'][0])) {
  6224.             foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
  6225.                 if ($mirror == $mir['attribs']['host']) {
  6226.                     $setmirror = &$this->_channelInfo['servers']['mirror'][$i];
  6227.                     break;
  6228.                 }
  6229.             }
  6230.         } else {
  6231.             if ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
  6232.                 $setmirror = &$this->_channelInfo['servers']['mirror'];
  6233.             }
  6234.         }
  6235.         if (!$setmirror) {
  6236.             $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
  6237.                 array('mirror' => $mirror));
  6238.             return false;
  6239.         }
  6240.         $set = array('attribs' => array('version' => $version), '_content' => $name);
  6241.         if (!isset($setmirror[$type]['function'])) {
  6242.             $setmirror[$type]['function'] = $set;
  6243.             $this->_isValid = false;
  6244.             return true;
  6245.         } elseif (!isset($setmirror[$type]['function'][0])) {
  6246.             $setmirror[$type]['function'] = array($setmirror[$type]['function']);
  6247.         }
  6248.         $setmirror[$type]['function'][] = $set;
  6249.         $this->_isValid = false;
  6250.         return true;
  6251.     }
  6252.  
  6253.     /**
  6254.      * @param string Resource Type this url links to
  6255.      * @param string URL
  6256.      * @param string|false mirror name, if this is not a primary server REST base URL
  6257.      */
  6258.     function setBaseURL($resourceType, $url, $mirror = false)
  6259.     {
  6260.         if ($mirror) {
  6261.             if (!isset($this->_channelInfo['servers']['mirror'])) {
  6262.                 $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
  6263.                     array('mirror' => $mirror));
  6264.                 return false;
  6265.             }
  6266.             $setmirror = false;
  6267.             if (isset($this->_channelInfo['servers']['mirror'][0])) {
  6268.                 foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
  6269.                     if ($mirror == $mir['attribs']['host']) {
  6270.                         $setmirror = &$this->_channelInfo['servers']['mirror'][$i];
  6271.                         break;
  6272.                     }
  6273.                 }
  6274.             } else {
  6275.                 if ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
  6276.                     $setmirror = &$this->_channelInfo['servers']['mirror'];
  6277.                 }
  6278.             }
  6279.         } else {
  6280.             $setmirror = &$this->_channelInfo['servers']['primary'];
  6281.         }
  6282.         $set = array('attribs' => array('type' => $resourceType), '_content' => $url);
  6283.         if (!isset($setmirror['rest'])) {
  6284.             $setmirror['rest'] = array();
  6285.         }
  6286.         if (!isset($setmirror['rest']['baseurl'])) {
  6287.             $setmirror['rest']['baseurl'] = $set;
  6288.             $this->_isValid = false;
  6289.             return true;
  6290.         } elseif (!isset($setmirror['rest']['baseurl'][0])) {
  6291.             $setmirror['rest']['baseurl'] = array($setmirror['rest']['baseurl']);
  6292.         }
  6293.         foreach ($setmirror['rest']['baseurl'] as $i => $url) {
  6294.             if ($url['attribs']['type'] == $resourceType) {
  6295.                 $this->_isValid = false;
  6296.                 $setmirror['rest']['baseurl'][$i] = $set;
  6297.                 return true;
  6298.             }
  6299.         }
  6300.         $setmirror['rest']['baseurl'][] = $set;
  6301.         $this->_isValid = false;
  6302.         return true;
  6303.     }
  6304.  
  6305.     /**
  6306.      * @param string mirror server
  6307.      * @param int mirror http port
  6308.      * @return boolean
  6309.      */
  6310.     function addMirror($server, $port = null)
  6311.     {
  6312.         if ($this->_channelInfo['name'] == '__uri') {
  6313.             return false; // the __uri channel cannot have mirrors by definition
  6314.         }
  6315.         $set = array('attribs' => array('host' => $server));
  6316.         if (is_numeric($port)) {
  6317.             $set['attribs']['port'] = $port;
  6318.         }
  6319.         if (!isset($this->_channelInfo['servers']['mirror'])) {
  6320.             $this->_channelInfo['servers']['mirror'] = $set;
  6321.             return true;
  6322.         } else {
  6323.             if (!isset($this->_channelInfo['servers']['mirror'][0])) {
  6324.                 $this->_channelInfo['servers']['mirror'] =
  6325.                     array($this->_channelInfo['servers']['mirror']);
  6326.             }
  6327.         }
  6328.         $this->_channelInfo['servers']['mirror'][] = $set;
  6329.         return true;
  6330.     }
  6331.  
  6332.     /**
  6333.      * Retrieve the name of the validation package for this channel
  6334.      * @return string|false
  6335.      */
  6336.     function getValidationPackage()
  6337.     {
  6338.         if (!$this->_isValid && !$this->validate()) {
  6339.             return false;
  6340.         }
  6341.         if (!isset($this->_channelInfo['validatepackage'])) {
  6342.             return array('attribs' => array('version' => 'default'),
  6343.                 '_content' => 'PEAR_Validate');
  6344.         }
  6345.         return $this->_channelInfo['validatepackage'];
  6346.     }
  6347.  
  6348.     /**
  6349.      * Retrieve the object that can be used for custom validation
  6350.      * @param string|false the name of the package to validate.  If the package is
  6351.      *                     the channel validation package, PEAR_Validate is returned
  6352.      * @return PEAR_Validate|false false is returned if the validation package
  6353.      *         cannot be located
  6354.      */
  6355.     function &getValidationObject($package = false)
  6356.     {
  6357.         if (!class_exists('PEAR_Validate')) {
  6358.             require_once 'phar://go-pear.phar/' . 'PEAR/Validate.php';
  6359.         }
  6360.         if (!$this->_isValid) {
  6361.             if (!$this->validate()) {
  6362.                 $a = false;
  6363.                 return $a;
  6364.             }
  6365.         }
  6366.         if (isset($this->_channelInfo['validatepackage'])) {
  6367.             if ($package == $this->_channelInfo['validatepackage']) {
  6368.                 // channel validation packages are always validated by PEAR_Validate
  6369.                 $val = &new PEAR_Validate;
  6370.                 return $val;
  6371.             }
  6372.             if (!class_exists(str_replace('.', '_',
  6373.                   $this->_channelInfo['validatepackage']['_content']))) {
  6374.                 if ($this->isIncludeable(str_replace('_', '/',
  6375.                       $this->_channelInfo['validatepackage']['_content']) . '.php')) {
  6376.                     include_once 'phar://go-pear.phar/' . str_replace('_', '/',
  6377.                         $this->_channelInfo['validatepackage']['_content']) . '.php';
  6378.                     $vclass = str_replace('.', '_',
  6379.                         $this->_channelInfo['validatepackage']['_content']);
  6380.                     $val = &new $vclass;
  6381.                 } else {
  6382.                     $a = false;
  6383.                     return $a;
  6384.                 }
  6385.             } else {
  6386.                 $vclass = str_replace('.', '_',
  6387.                     $this->_channelInfo['validatepackage']['_content']);
  6388.                 $val = &new $vclass;
  6389.             }
  6390.         } else {
  6391.             $val = &new PEAR_Validate;
  6392.         }
  6393.         return $val;
  6394.     }
  6395.  
  6396.     function isIncludeable($path)
  6397.     {
  6398.         $possibilities = explode(PATH_SEPARATOR, ini_get('include_path'));
  6399.         foreach ($possibilities as $dir) {
  6400.             if (file_exists($dir . DIRECTORY_SEPARATOR . $path)
  6401.                   && is_readable($dir . DIRECTORY_SEPARATOR . $path)) {
  6402.                 return true;
  6403.             }
  6404.         }
  6405.         return false;
  6406.     }
  6407.  
  6408.     /**
  6409.      * This function is used by the channel updater and retrieves a value set by
  6410.      * the registry, or the current time if it has not been set
  6411.      * @return string
  6412.      */
  6413.     function lastModified()
  6414.     {
  6415.         if (isset($this->_channelInfo['_lastmodified'])) {
  6416.             return $this->_channelInfo['_lastmodified'];
  6417.         }
  6418.         return time();
  6419.     }
  6420. }
  6421. ?>
  6422. <?php
  6423. /**
  6424.  * PEAR_ChannelFile_Parser for parsing channel.xml
  6425.  *
  6426.  * PHP versions 4 and 5
  6427.  *
  6428.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  6429.  * that is available through the world-wide-web at the following URI:
  6430.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  6431.  * the PHP License and are unable to obtain it through the web, please
  6432.  * send a note to license@php.net so we can mail you a copy immediately.
  6433.  *
  6434.  * @category   pear
  6435.  * @package    PEAR
  6436.  * @author     Greg Beaver <cellog@php.net>
  6437.  * @copyright  1997-2008 The PHP Group
  6438.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  6439.  * @version    CVS: $Id: Parser.php,v 1.5 2008/01/03 20:26:36 cellog Exp $
  6440.  * @link       http://pear.php.net/package/PEAR
  6441.  * @since      File available since Release 1.4.0a1
  6442.  */
  6443.  
  6444. /**
  6445.  * base xml parser class
  6446.  */
  6447. require_once 'phar://go-pear.phar/' . 'PEAR/XMLParser.php';
  6448. require_once 'phar://go-pear.phar/' . 'PEAR/ChannelFile.php';
  6449. /**
  6450.  * Parser for channel.xml
  6451.  * @category   pear
  6452.  * @package    PEAR
  6453.  * @author     Greg Beaver <cellog@php.net>
  6454.  * @copyright  1997-2008 The PHP Group
  6455.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  6456.  * @version    Release: 1.7.1
  6457.  * @link       http://pear.php.net/package/PEAR
  6458.  * @since      Class available since Release 1.4.0a1
  6459.  */
  6460. class PEAR_ChannelFile_Parser extends PEAR_XMLParser
  6461. {
  6462.     var $_config;
  6463.     var $_logger;
  6464.     var $_registry;
  6465.  
  6466.     function setConfig(&$c)
  6467.     {
  6468.         $this->_config = &$c;
  6469.         $this->_registry = &$c->getRegistry();
  6470.     }
  6471.  
  6472.     function setLogger(&$l)
  6473.     {
  6474.         $this->_logger = &$l;
  6475.     }
  6476.  
  6477.     function parse($data, $file)
  6478.     {
  6479.         if (PEAR::isError($err = parent::parse($data, $file))) {
  6480.             return $err;
  6481.         }
  6482.         $ret = new PEAR_ChannelFile;
  6483.         $ret->setConfig($this->_config);
  6484.         if (isset($this->_logger)) {
  6485.             $ret->setLogger($this->_logger);
  6486.         }
  6487.         $ret->fromArray($this->_unserializedData);
  6488.         // make sure the filelist is in the easy to read format needed
  6489.         $ret->flattenFilelist();
  6490.         $ret->setPackagefile($file, $archive);
  6491.         return $ret;
  6492.     }
  6493. }
  6494. ?><?php
  6495. /**
  6496.  * PEAR_Command, command pattern class
  6497.  *
  6498.  * PHP versions 4 and 5
  6499.  *
  6500.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  6501.  * that is available through the world-wide-web at the following URI:
  6502.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  6503.  * the PHP License and are unable to obtain it through the web, please
  6504.  * send a note to license@php.net so we can mail you a copy immediately.
  6505.  *
  6506.  * @category   pear
  6507.  * @package    PEAR
  6508.  * @author     Stig Bakken <ssb@php.net>
  6509.  * @author     Greg Beaver <cellog@php.net>
  6510.  * @copyright  1997-2008 The PHP Group
  6511.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  6512.  * @version    CVS: $Id: Command.php,v 1.39 2008/01/03 20:26:34 cellog Exp $
  6513.  * @link       http://pear.php.net/package/PEAR
  6514.  * @since      File available since Release 0.1
  6515.  */
  6516.  
  6517. /**
  6518.  * Needed for error handling
  6519.  */
  6520. require_once 'phar://go-pear.phar/' . 'PEAR.php';
  6521. require_once 'phar://go-pear.phar/' . 'PEAR/Frontend.php';
  6522. require_once 'phar://go-pear.phar/' . 'PEAR/XMLParser.php';
  6523.  
  6524. /**
  6525.  * List of commands and what classes they are implemented in.
  6526.  * @var array command => implementing class
  6527.  */
  6528. $GLOBALS['_PEAR_Command_commandlist'] = array();
  6529.  
  6530. /**
  6531.  * List of commands and their descriptions
  6532.  * @var array command => description
  6533.  */
  6534. $GLOBALS['_PEAR_Command_commanddesc'] = array();
  6535.  
  6536. /**
  6537.  * List of shortcuts to common commands.
  6538.  * @var array shortcut => command
  6539.  */
  6540. $GLOBALS['_PEAR_Command_shortcuts'] = array();
  6541.  
  6542. /**
  6543.  * Array of command objects
  6544.  * @var array class => object
  6545.  */
  6546. $GLOBALS['_PEAR_Command_objects'] = array();
  6547.  
  6548. /**
  6549.  * PEAR command class, a simple factory class for administrative
  6550.  * commands.
  6551.  *
  6552.  * How to implement command classes:
  6553.  *
  6554.  * - The class must be called PEAR_Command_Nnn, installed in the
  6555.  *   "PEAR/Common" subdir, with a method called getCommands() that
  6556.  *   returns an array of the commands implemented by the class (see
  6557.  *   PEAR/Command/Install.php for an example).
  6558.  *
  6559.  * - The class must implement a run() function that is called with three
  6560.  *   params:
  6561.  *
  6562.  *    (string) command name
  6563.  *    (array)  assoc array with options, freely defined by each
  6564.  *             command, for example:
  6565.  *             array('force' => true)
  6566.  *    (array)  list of the other parameters
  6567.  *
  6568.  *   The run() function returns a PEAR_CommandResponse object.  Use
  6569.  *   these methods to get information:
  6570.  *
  6571.  *    int getStatus()   Returns PEAR_COMMAND_(SUCCESS|FAILURE|PARTIAL)
  6572.  *                      *_PARTIAL means that you need to issue at least
  6573.  *                      one more command to complete the operation
  6574.  *                      (used for example for validation steps).
  6575.  *
  6576.  *    string getMessage()  Returns a message for the user.  Remember,
  6577.  *                         no HTML or other interface-specific markup.
  6578.  *
  6579.  *   If something unexpected happens, run() returns a PEAR error.
  6580.  *
  6581.  * - DON'T OUTPUT ANYTHING! Return text for output instead.
  6582.  *
  6583.  * - DON'T USE HTML! The text you return will be used from both Gtk,
  6584.  *   web and command-line interfaces, so for now, keep everything to
  6585.  *   plain text.
  6586.  *
  6587.  * - DON'T USE EXIT OR DIE! Always use pear errors.  From static
  6588.  *   classes do PEAR::raiseError(), from other classes do
  6589.  *   $this->raiseError().
  6590.  * @category   pear
  6591.  * @package    PEAR
  6592.  * @author     Stig Bakken <ssb@php.net>
  6593.  * @author     Greg Beaver <cellog@php.net>
  6594.  * @copyright  1997-2008 The PHP Group
  6595.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  6596.  * @version    Release: 1.7.1
  6597.  * @link       http://pear.php.net/package/PEAR
  6598.  * @since      Class available since Release 0.1
  6599.  */
  6600. class PEAR_Command
  6601. {
  6602.     // {{{ factory()
  6603.  
  6604.     /**
  6605.      * Get the right object for executing a command.
  6606.      *
  6607.      * @param string $command The name of the command
  6608.      * @param object $config  Instance of PEAR_Config object
  6609.      *
  6610.      * @return object the command object or a PEAR error
  6611.      *
  6612.      * @access public
  6613.      * @static
  6614.      */
  6615.     function &factory($command, &$config)
  6616.     {
  6617.         if (empty($GLOBALS['_PEAR_Command_commandlist'])) {
  6618.             PEAR_Command::registerCommands();
  6619.         }
  6620.         if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) {
  6621.             $command = $GLOBALS['_PEAR_Command_shortcuts'][$command];
  6622.         }
  6623.         if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) {
  6624.             $a = PEAR::raiseError("unknown command `$command'");
  6625.             return $a;
  6626.         }
  6627.         $class = $GLOBALS['_PEAR_Command_commandlist'][$command];
  6628.         if (!class_exists($class)) {
  6629.             require_once $GLOBALS['_PEAR_Command_objects'][$class];
  6630.         }
  6631.         if (!class_exists($class)) {
  6632.             $a = PEAR::raiseError("unknown command `$command'");
  6633.             return $a;
  6634.         }
  6635.         $ui =& PEAR_Command::getFrontendObject();
  6636.         $obj = &new $class($ui, $config);
  6637.         return $obj;
  6638.     }
  6639.  
  6640.     // }}}
  6641.     // {{{ & getObject()
  6642.     function &getObject($command)
  6643.     {
  6644.         $class = $GLOBALS['_PEAR_Command_commandlist'][$command];
  6645.         if (!class_exists($class)) {
  6646.             require_once $GLOBALS['_PEAR_Command_objects'][$class];
  6647.         }
  6648.         if (!class_exists($class)) {
  6649.             return PEAR::raiseError("unknown command `$command'");
  6650.         }
  6651.         $ui =& PEAR_Command::getFrontendObject();
  6652.         $config = &PEAR_Config::singleton();
  6653.         $obj = &new $class($ui, $config);
  6654.         return $obj;
  6655.     }
  6656.  
  6657.     // }}}
  6658.     // {{{ & getFrontendObject()
  6659.  
  6660.     /**
  6661.      * Get instance of frontend object.
  6662.      *
  6663.      * @return object|PEAR_Error
  6664.      * @static
  6665.      */
  6666.     function &getFrontendObject()
  6667.     {
  6668.         $a = &PEAR_Frontend::singleton();
  6669.         return $a;
  6670.     }
  6671.  
  6672.     // }}}
  6673.     // {{{ & setFrontendClass()
  6674.  
  6675.     /**
  6676.      * Load current frontend class.
  6677.      *
  6678.      * @param string $uiclass Name of class implementing the frontend
  6679.      *
  6680.      * @return object the frontend object, or a PEAR error
  6681.      * @static
  6682.      */
  6683.     function &setFrontendClass($uiclass)
  6684.     {
  6685.         $a = &PEAR_Frontend::setFrontendClass($uiclass);
  6686.         return $a;
  6687.     }
  6688.  
  6689.     // }}}
  6690.     // {{{ setFrontendType()
  6691.  
  6692.     /**
  6693.      * Set current frontend.
  6694.      *
  6695.      * @param string $uitype Name of the frontend type (for example "CLI")
  6696.      *
  6697.      * @return object the frontend object, or a PEAR error
  6698.      * @static
  6699.      */
  6700.     function setFrontendType($uitype)
  6701.     {
  6702.         $uiclass = 'PEAR_Frontend_' . $uitype;
  6703.         return PEAR_Command::setFrontendClass($uiclass);
  6704.     }
  6705.  
  6706.     // }}}
  6707.     // {{{ registerCommands()
  6708.  
  6709.     /**
  6710.      * Scan through the Command directory looking for classes
  6711.      * and see what commands they implement.
  6712.      *
  6713.      * @param bool   (optional) if FALSE (default), the new list of
  6714.      *               commands should replace the current one.  If TRUE,
  6715.      *               new entries will be merged with old.
  6716.      *
  6717.      * @param string (optional) where (what directory) to look for
  6718.      *               classes, defaults to the Command subdirectory of
  6719.      *               the directory from where this file (__FILE__) is
  6720.      *               included.
  6721.      *
  6722.      * @return bool TRUE on success, a PEAR error on failure
  6723.      *
  6724.      * @access public
  6725.      * @static
  6726.      */
  6727.     function registerCommands($merge = false, $dir = null)
  6728.     {
  6729.         $parser = new PEAR_XMLParser;
  6730.         if ($dir === null) {
  6731.             $dir = dirname(__FILE__) . '/Command';
  6732.         }
  6733.         if (!is_dir($dir)) {
  6734.             return PEAR::raiseError("registerCommands: opendir($dir) '$dir' does not exist or is not a directory");
  6735.         }
  6736.         $dp = @opendir($dir);
  6737.         if (empty($dp)) {
  6738.             return PEAR::raiseError("registerCommands: opendir($dir) failed");
  6739.         }
  6740.         if (!$merge) {
  6741.             $GLOBALS['_PEAR_Command_commandlist'] = array();
  6742.         }
  6743.         while ($entry = readdir($dp)) {
  6744.             if ($entry{0} == '.' || substr($entry, -4) != '.xml') {
  6745.                 continue;
  6746.             }
  6747.             $class = "PEAR_Command_".substr($entry, 0, -4);
  6748.             $file = "$dir/$entry";
  6749.             $parser->parse(file_get_contents($file));
  6750.             $implements = $parser->getData();
  6751.             // List of commands
  6752.             if (empty($GLOBALS['_PEAR_Command_objects'][$class])) {
  6753.                 $GLOBALS['_PEAR_Command_objects'][$class] = "$dir/" . substr($entry, 0, -4) .
  6754.                     '.php';
  6755.             }
  6756.             foreach ($implements as $command => $desc) {
  6757.                 if ($command == 'attribs') {
  6758.                     continue;
  6759.                 }
  6760.                 if (isset($GLOBALS['_PEAR_Command_commandlist'][$command])) {
  6761.                     return PEAR::raiseError('Command "' . $command . '" already registered in ' .
  6762.                         'class "' . $GLOBALS['_PEAR_Command_commandlist'][$command] . '"');
  6763.                 }
  6764.                 $GLOBALS['_PEAR_Command_commandlist'][$command] = $class;
  6765.                 $GLOBALS['_PEAR_Command_commanddesc'][$command] = $desc['summary'];
  6766.                 if (isset($desc['shortcut'])) {
  6767.                     $shortcut = $desc['shortcut'];
  6768.                     if (isset($GLOBALS['_PEAR_Command_shortcuts'][$shortcut])) {
  6769.                         return PEAR::raiseError('Command shortcut "' . $shortcut . '" already ' .
  6770.                             'registered to command "' . $command . '" in class "' .
  6771.                             $GLOBALS['_PEAR_Command_commandlist'][$command] . '"');
  6772.                     }
  6773.                     $GLOBALS['_PEAR_Command_shortcuts'][$shortcut] = $command;
  6774.                 }
  6775.                 if (isset($desc['options']) && $desc['options']) {
  6776.                     foreach ($desc['options'] as $oname => $option) {
  6777.                         if (isset($option['shortopt']) && strlen($option['shortopt']) > 1) {
  6778.                             return PEAR::raiseError('Option "' . $oname . '" short option "' .
  6779.                                 $option['shortopt'] . '" must be ' .
  6780.                                 'only 1 character in Command "' . $command . '" in class "' .
  6781.                                 $class . '"');
  6782.                         }
  6783.                     }
  6784.                 }
  6785.             }
  6786.         }
  6787.         ksort($GLOBALS['_PEAR_Command_shortcuts']);
  6788.         ksort($GLOBALS['_PEAR_Command_commandlist']);
  6789.         @closedir($dp);
  6790.         return true;
  6791.     }
  6792.  
  6793.     // }}}
  6794.     // {{{ getCommands()
  6795.  
  6796.     /**
  6797.      * Get the list of currently supported commands, and what
  6798.      * classes implement them.
  6799.      *
  6800.      * @return array command => implementing class
  6801.      *
  6802.      * @access public
  6803.      * @static
  6804.      */
  6805.     function getCommands()
  6806.     {
  6807.         if (empty($GLOBALS['_PEAR_Command_commandlist'])) {
  6808.             PEAR_Command::registerCommands();
  6809.         }
  6810.         return $GLOBALS['_PEAR_Command_commandlist'];
  6811.     }
  6812.  
  6813.     // }}}
  6814.     // {{{ getShortcuts()
  6815.  
  6816.     /**
  6817.      * Get the list of command shortcuts.
  6818.      *
  6819.      * @return array shortcut => command
  6820.      *
  6821.      * @access public
  6822.      * @static
  6823.      */
  6824.     function getShortcuts()
  6825.     {
  6826.         if (empty($GLOBALS['_PEAR_Command_shortcuts'])) {
  6827.             PEAR_Command::registerCommands();
  6828.         }
  6829.         return $GLOBALS['_PEAR_Command_shortcuts'];
  6830.     }
  6831.  
  6832.     // }}}
  6833.     // {{{ getGetoptArgs()
  6834.  
  6835.     /**
  6836.      * Compiles arguments for getopt.
  6837.      *
  6838.      * @param string $command     command to get optstring for
  6839.      * @param string $short_args  (reference) short getopt format
  6840.      * @param array  $long_args   (reference) long getopt format
  6841.      *
  6842.      * @return void
  6843.      *
  6844.      * @access public
  6845.      * @static
  6846.      */
  6847.     function getGetoptArgs($command, &$short_args, &$long_args)
  6848.     {
  6849.         if (empty($GLOBALS['_PEAR_Command_commandlist'])) {
  6850.             PEAR_Command::registerCommands();
  6851.         }
  6852.         if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) {
  6853.             $command = $GLOBALS['_PEAR_Command_shortcuts'][$command];
  6854.         }
  6855.         if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) {
  6856.             return null;
  6857.         }
  6858.         $obj = &PEAR_Command::getObject($command);
  6859.         return $obj->getGetoptArgs($command, $short_args, $long_args);
  6860.     }
  6861.  
  6862.     // }}}
  6863.     // {{{ getDescription()
  6864.  
  6865.     /**
  6866.      * Get description for a command.
  6867.      *
  6868.      * @param  string $command Name of the command
  6869.      *
  6870.      * @return string command description
  6871.      *
  6872.      * @access public
  6873.      * @static
  6874.      */
  6875.     function getDescription($command)
  6876.     {
  6877.         if (!isset($GLOBALS['_PEAR_Command_commanddesc'][$command])) {
  6878.             return null;
  6879.         }
  6880.         return $GLOBALS['_PEAR_Command_commanddesc'][$command];
  6881.     }
  6882.  
  6883.     // }}}
  6884.     // {{{ getHelp()
  6885.  
  6886.     /**
  6887.      * Get help for command.
  6888.      *
  6889.      * @param string $command Name of the command to return help for
  6890.      *
  6891.      * @access public
  6892.      * @static
  6893.      */
  6894.     function getHelp($command)
  6895.     {
  6896.         $cmds = PEAR_Command::getCommands();
  6897.         if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) {
  6898.             $command = $GLOBALS['_PEAR_Command_shortcuts'][$command];
  6899.         }
  6900.         if (isset($cmds[$command])) {
  6901.             $obj = &PEAR_Command::getObject($command);
  6902.             return $obj->getHelp($command);
  6903.         }
  6904.         return false;
  6905.     }
  6906.     // }}}
  6907. }
  6908.  
  6909. ?>
  6910. <?php
  6911. /**
  6912.  * PEAR_Command_Common base class
  6913.  *
  6914.  * PHP versions 4 and 5
  6915.  *
  6916.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  6917.  * that is available through the world-wide-web at the following URI:
  6918.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  6919.  * the PHP License and are unable to obtain it through the web, please
  6920.  * send a note to license@php.net so we can mail you a copy immediately.
  6921.  *
  6922.  * @category   pear
  6923.  * @package    PEAR
  6924.  * @author     Stig Bakken <ssb@php.net>
  6925.  * @author     Greg Beaver <cellog@php.net>
  6926.  * @copyright  1997-2008 The PHP Group
  6927.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  6928.  * @version    CVS: $Id: Common.php,v 1.36 2008/01/03 20:26:36 cellog Exp $
  6929.  * @link       http://pear.php.net/package/PEAR
  6930.  * @since      File available since Release 0.1
  6931.  */
  6932.  
  6933. /**
  6934.  * base class
  6935.  */
  6936. require_once 'phar://go-pear.phar/' . 'PEAR.php';
  6937.  
  6938. /**
  6939.  * PEAR commands base class
  6940.  *
  6941.  * @category   pear
  6942.  * @package    PEAR
  6943.  * @author     Stig Bakken <ssb@php.net>
  6944.  * @author     Greg Beaver <cellog@php.net>
  6945.  * @copyright  1997-2008 The PHP Group
  6946.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  6947.  * @version    Release: 1.7.1
  6948.  * @link       http://pear.php.net/package/PEAR
  6949.  * @since      Class available since Release 0.1
  6950.  */
  6951. class PEAR_Command_Common extends PEAR
  6952. {
  6953.     // {{{ properties
  6954.  
  6955.     /**
  6956.      * PEAR_Config object used to pass user system and configuration
  6957.      * on when executing commands
  6958.      *
  6959.      * @var PEAR_Config
  6960.      */
  6961.     var $config;
  6962.     /**
  6963.      * @var PEAR_Registry
  6964.      * @access protected
  6965.      */
  6966.     var $_registry;
  6967.  
  6968.     /**
  6969.      * User Interface object, for all interaction with the user.
  6970.      * @var object
  6971.      */
  6972.     var $ui;
  6973.  
  6974.     var $_deps_rel_trans = array(
  6975.                                  'lt' => '<',
  6976.                                  'le' => '<=',
  6977.                                  'eq' => '=',
  6978.                                  'ne' => '!=',
  6979.                                  'gt' => '>',
  6980.                                  'ge' => '>=',
  6981.                                  'has' => '=='
  6982.                                  );
  6983.  
  6984.     var $_deps_type_trans = array(
  6985.                                   'pkg' => 'package',
  6986.                                   'ext' => 'extension',
  6987.                                   'php' => 'PHP',
  6988.                                   'prog' => 'external program',
  6989.                                   'ldlib' => 'external library for linking',
  6990.                                   'rtlib' => 'external runtime library',
  6991.                                   'os' => 'operating system',
  6992.                                   'websrv' => 'web server',
  6993.                                   'sapi' => 'SAPI backend'
  6994.                                   );
  6995.  
  6996.     // }}}
  6997.     // {{{ constructor
  6998.  
  6999.     /**
  7000.      * PEAR_Command_Common constructor.
  7001.      *
  7002.      * @access public
  7003.      */
  7004.     function PEAR_Command_Common(&$ui, &$config)
  7005.     {
  7006.         parent::PEAR();
  7007.         $this->config = &$config;
  7008.         $this->ui = &$ui;
  7009.     }
  7010.  
  7011.     // }}}
  7012.  
  7013.     // {{{ getCommands()
  7014.  
  7015.     /**
  7016.      * Return a list of all the commands defined by this class.
  7017.      * @return array list of commands
  7018.      * @access public
  7019.      */
  7020.     function getCommands()
  7021.     {
  7022.         $ret = array();
  7023.         foreach (array_keys($this->commands) as $command) {
  7024.             $ret[$command] = $this->commands[$command]['summary'];
  7025.         }
  7026.         return $ret;
  7027.     }
  7028.  
  7029.     // }}}
  7030.     // {{{ getShortcuts()
  7031.  
  7032.     /**
  7033.      * Return a list of all the command shortcuts defined by this class.
  7034.      * @return array shortcut => command
  7035.      * @access public
  7036.      */
  7037.     function getShortcuts()
  7038.     {
  7039.         $ret = array();
  7040.         foreach (array_keys($this->commands) as $command) {
  7041.             if (isset($this->commands[$command]['shortcut'])) {
  7042.                 $ret[$this->commands[$command]['shortcut']] = $command;
  7043.             }
  7044.         }
  7045.         return $ret;
  7046.     }
  7047.  
  7048.     // }}}
  7049.     // {{{ getOptions()
  7050.  
  7051.     function getOptions($command)
  7052.     {
  7053.         $shortcuts = $this->getShortcuts();
  7054.         if (isset($shortcuts[$command])) {
  7055.             $command = $shortcuts[$command];
  7056.         }
  7057.         if (isset($this->commands[$command]) &&
  7058.               isset($this->commands[$command]['options'])) {
  7059.             return $this->commands[$command]['options'];
  7060.         } else {
  7061.             return null;
  7062.         }
  7063.     }
  7064.  
  7065.     // }}}
  7066.     // {{{ getGetoptArgs()
  7067.  
  7068.     function getGetoptArgs($command, &$short_args, &$long_args)
  7069.     {
  7070.         $short_args = "";
  7071.         $long_args = array();
  7072.         if (empty($this->commands[$command]) || empty($this->commands[$command]['options'])) {
  7073.             return;
  7074.         }
  7075.         reset($this->commands[$command]['options']);
  7076.         while (list($option, $info) = each($this->commands[$command]['options'])) {
  7077.             $larg = $sarg = '';
  7078.             if (isset($info['arg'])) {
  7079.                 if ($info['arg']{0} == '(') {
  7080.                     $larg = '==';
  7081.                     $sarg = '::';
  7082.                     $arg = substr($info['arg'], 1, -1);
  7083.                 } else {
  7084.                     $larg = '=';
  7085.                     $sarg = ':';
  7086.                     $arg = $info['arg'];
  7087.                 }
  7088.             }
  7089.             if (isset($info['shortopt'])) {
  7090.                 $short_args .= $info['shortopt'] . $sarg;
  7091.             }
  7092.             $long_args[] = $option . $larg;
  7093.         }
  7094.     }
  7095.  
  7096.     // }}}
  7097.     // {{{ getHelp()
  7098.     /**
  7099.     * Returns the help message for the given command
  7100.     *
  7101.     * @param string $command The command
  7102.     * @return mixed A fail string if the command does not have help or
  7103.     *               a two elements array containing [0]=>help string,
  7104.     *               [1]=> help string for the accepted cmd args
  7105.     */
  7106.     function getHelp($command)
  7107.     {
  7108.         $config = &PEAR_Config::singleton();
  7109.         if (!isset($this->commands[$command])) {
  7110.             return "No such command \"$command\"";
  7111.         }
  7112.         $help = null;
  7113.         if (isset($this->commands[$command]['doc'])) {
  7114.             $help = $this->commands[$command]['doc'];
  7115.         }
  7116.         if (empty($help)) {
  7117.             // XXX (cox) Fallback to summary if there is no doc (show both?)
  7118.             if (!isset($this->commands[$command]['summary'])) {
  7119.                 return "No help for command \"$command\"";
  7120.             }
  7121.             $help = $this->commands[$command]['summary'];
  7122.         }
  7123.         if (preg_match_all('/{config\s+([^\}]+)}/e', $help, $matches)) {
  7124.             foreach($matches[0] as $k => $v) {
  7125.                 $help = preg_replace("/$v/", $config->get($matches[1][$k]), $help);
  7126.             }
  7127.         }
  7128.         return array($help, $this->getHelpArgs($command));
  7129.     }
  7130.  
  7131.     // }}}
  7132.     // {{{ getHelpArgs()
  7133.     /**
  7134.     * Returns the help for the accepted arguments of a command
  7135.     *
  7136.     * @param  string $command
  7137.     * @return string The help string
  7138.     */
  7139.     function getHelpArgs($command)
  7140.     {
  7141.         if (isset($this->commands[$command]['options']) &&
  7142.             count($this->commands[$command]['options']))
  7143.         {
  7144.             $help = "Options:\n";
  7145.             foreach ($this->commands[$command]['options'] as $k => $v) {
  7146.                 if (isset($v['arg'])) {
  7147.                     if ($v['arg'][0] == '(') {
  7148.                         $arg = substr($v['arg'], 1, -1);
  7149.                         $sapp = " [$arg]";
  7150.                         $lapp = "[=$arg]";
  7151.                     } else {
  7152.                         $sapp = " $v[arg]";
  7153.                         $lapp = "=$v[arg]";
  7154.                     }
  7155.                 } else {
  7156.                     $sapp = $lapp = "";
  7157.                 }
  7158.                 if (isset($v['shortopt'])) {
  7159.                     $s = $v['shortopt'];
  7160.                     $help .= "  -$s$sapp, --$k$lapp\n";
  7161.                 } else {
  7162.                     $help .= "  --$k$lapp\n";
  7163.                 }
  7164.                 $p = "        ";
  7165.                 $doc = rtrim(str_replace("\n", "\n$p", $v['doc']));
  7166.                 $help .= "        $doc\n";
  7167.             }
  7168.             return $help;
  7169.         }
  7170.         return null;
  7171.     }
  7172.  
  7173.     // }}}
  7174.     // {{{ run()
  7175.  
  7176.     function run($command, $options, $params)
  7177.     {
  7178.         if (empty($this->commands[$command]['function'])) {
  7179.             // look for shortcuts
  7180.             foreach (array_keys($this->commands) as $cmd) {
  7181.                 if (isset($this->commands[$cmd]['shortcut']) && $this->commands[$cmd]['shortcut'] == $command) {
  7182.                     if (empty($this->commands[$cmd]['function'])) {
  7183.                         return $this->raiseError("unknown command `$command'");
  7184.                     } else {
  7185.                         $func = $this->commands[$cmd]['function'];
  7186.                     }
  7187.                     $command = $cmd;
  7188.                     break;
  7189.                 }
  7190.             }
  7191.         } else {
  7192.             $func = $this->commands[$command]['function'];
  7193.         }
  7194.         return $this->$func($command, $options, $params);
  7195.     }
  7196.  
  7197.     // }}}
  7198. }
  7199.  
  7200. ?>
  7201. <?php
  7202. /**
  7203.  * PEAR_Command_Install (install, upgrade, upgrade-all, uninstall, bundle, run-scripts commands)
  7204.  *
  7205.  * PHP versions 4 and 5
  7206.  *
  7207.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  7208.  * that is available through the world-wide-web at the following URI:
  7209.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  7210.  * the PHP License and are unable to obtain it through the web, please
  7211.  * send a note to license@php.net so we can mail you a copy immediately.
  7212.  *
  7213.  * @category   pear
  7214.  * @package    PEAR
  7215.  * @author     Stig Bakken <ssb@php.net>
  7216.  * @author     Greg Beaver <cellog@php.net>
  7217.  * @copyright  1997-2008 The PHP Group
  7218.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  7219.  * @version    CVS: $Id: Install.php,v 1.140 2008/01/29 03:21:01 cellog Exp $
  7220.  * @link       http://pear.php.net/package/PEAR
  7221.  * @since      File available since Release 0.1
  7222.  */
  7223.  
  7224. /**
  7225.  * base class
  7226.  */
  7227. require_once 'phar://go-pear.phar/' . 'PEAR/Command/Common.php';
  7228.  
  7229. /**
  7230.  * PEAR commands for installation or deinstallation/upgrading of
  7231.  * packages.
  7232.  *
  7233.  * @category   pear
  7234.  * @package    PEAR
  7235.  * @author     Stig Bakken <ssb@php.net>
  7236.  * @author     Greg Beaver <cellog@php.net>
  7237.  * @copyright  1997-2008 The PHP Group
  7238.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  7239.  * @version    Release: 1.7.1
  7240.  * @link       http://pear.php.net/package/PEAR
  7241.  * @since      Class available since Release 0.1
  7242.  */
  7243. class PEAR_Command_Install extends PEAR_Command_Common
  7244. {
  7245.     // {{{ properties
  7246.  
  7247.     var $commands = array(
  7248.         'install' => array(
  7249.             'summary' => 'Install Package',
  7250.             'function' => 'doInstall',
  7251.             'shortcut' => 'i',
  7252.             'options' => array(
  7253.                 'force' => array(
  7254.                     'shortopt' => 'f',
  7255.                     'doc' => 'will overwrite newer installed packages',
  7256.                     ),
  7257.                 'loose' => array(
  7258.                     'shortopt' => 'l',
  7259.                     'doc' => 'do not check for recommended dependency version',
  7260.                     ),
  7261.                 'nodeps' => array(
  7262.                     'shortopt' => 'n',
  7263.                     'doc' => 'ignore dependencies, install anyway',
  7264.                     ),
  7265.                 'register-only' => array(
  7266.                     'shortopt' => 'r',
  7267.                     'doc' => 'do not install files, only register the package as installed',
  7268.                     ),
  7269.                 'soft' => array(
  7270.                     'shortopt' => 's',
  7271.                     'doc' => 'soft install, fail silently, or upgrade if already installed',
  7272.                     ),
  7273.                 'nobuild' => array(
  7274.                     'shortopt' => 'B',
  7275.                     'doc' => 'don\'t build C extensions',
  7276.                     ),
  7277.                 'nocompress' => array(
  7278.                     'shortopt' => 'Z',
  7279.                     'doc' => 'request uncompressed files when downloading',
  7280.                     ),
  7281.                 'installroot' => array(
  7282.                     'shortopt' => 'R',
  7283.                     'arg' => 'DIR',
  7284.                     'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM',
  7285.                     ),
  7286.                 'packagingroot' => array(
  7287.                     'shortopt' => 'P',
  7288.                     'arg' => 'DIR',
  7289.                     'doc' => 'root directory used when packaging files, like RPM packaging',
  7290.                     ),
  7291.                 'ignore-errors' => array(
  7292.                     'doc' => 'force install even if there were errors',
  7293.                     ),
  7294.                 'alldeps' => array(
  7295.                     'shortopt' => 'a',
  7296.                     'doc' => 'install all required and optional dependencies',
  7297.                     ),
  7298.                 'onlyreqdeps' => array(
  7299.                     'shortopt' => 'o',
  7300.                     'doc' => 'install all required dependencies',
  7301.                     ),
  7302.                 'offline' => array(
  7303.                     'shortopt' => 'O',
  7304.                     'doc' => 'do not attempt to download any urls or contact channels',
  7305.                     ),
  7306.                 'pretend' => array(
  7307.                     'shortopt' => 'p',
  7308.                     'doc' => 'Only list the packages that would be downloaded',
  7309.                     ),
  7310.                 ),
  7311.             'doc' => '[channel/]<package> ...
  7312. Installs one or more PEAR packages.  You can specify a package to
  7313. install in four ways:
  7314.  
  7315. "Package-1.0.tgz" : installs from a local file
  7316.  
  7317. "http://example.com/Package-1.0.tgz" : installs from
  7318. anywhere on the net.
  7319.  
  7320. "package.xml" : installs the package described in
  7321. package.xml.  Useful for testing, or for wrapping a PEAR package in
  7322. another package manager such as RPM.
  7323.  
  7324. "Package[-version/state][.tar]" : queries your default channel\'s server
  7325. ({config master_server}) and downloads the newest package with
  7326. the preferred quality/state ({config preferred_state}).
  7327.  
  7328. To retrieve Package version 1.1, use "Package-1.1," to retrieve
  7329. Package state beta, use "Package-beta."  To retrieve an uncompressed
  7330. file, append .tar (make sure there is no file by the same name first)
  7331.  
  7332. To download a package from another channel, prefix with the channel name like
  7333. "channel/Package"
  7334.  
  7335. More than one package may be specified at once.  It is ok to mix these
  7336. four ways of specifying packages.
  7337. '),
  7338.         'upgrade' => array(
  7339.             'summary' => 'Upgrade Package',
  7340.             'function' => 'doInstall',
  7341.             'shortcut' => 'up',
  7342.             'options' => array(
  7343.                 'force' => array(
  7344.                     'shortopt' => 'f',
  7345.                     'doc' => 'overwrite newer installed packages',
  7346.                     ),
  7347.                 'loose' => array(
  7348.                     'shortopt' => 'l',
  7349.                     'doc' => 'do not check for recommended dependency version',
  7350.                     ),
  7351.                 'nodeps' => array(
  7352.                     'shortopt' => 'n',
  7353.                     'doc' => 'ignore dependencies, upgrade anyway',
  7354.                     ),
  7355.                 'register-only' => array(
  7356.                     'shortopt' => 'r',
  7357.                     'doc' => 'do not install files, only register the package as upgraded',
  7358.                     ),
  7359.                 'nobuild' => array(
  7360.                     'shortopt' => 'B',
  7361.                     'doc' => 'don\'t build C extensions',
  7362.                     ),
  7363.                 'nocompress' => array(
  7364.                     'shortopt' => 'Z',
  7365.                     'doc' => 'request uncompressed files when downloading',
  7366.                     ),
  7367.                 'installroot' => array(
  7368.                     'shortopt' => 'R',
  7369.                     'arg' => 'DIR',
  7370.                     'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)',
  7371.                     ),
  7372.                 'ignore-errors' => array(
  7373.                     'doc' => 'force install even if there were errors',
  7374.                     ),
  7375.                 'alldeps' => array(
  7376.                     'shortopt' => 'a',
  7377.                     'doc' => 'install all required and optional dependencies',
  7378.                     ),
  7379.                 'onlyreqdeps' => array(
  7380.                     'shortopt' => 'o',
  7381.                     'doc' => 'install all required dependencies',
  7382.                     ),
  7383.                 'offline' => array(
  7384.                     'shortopt' => 'O',
  7385.                     'doc' => 'do not attempt to download any urls or contact channels',
  7386.                     ),
  7387.                 'pretend' => array(
  7388.                     'shortopt' => 'p',
  7389.                     'doc' => 'Only list the packages that would be downloaded',
  7390.                     ),
  7391.                 ),
  7392.             'doc' => '<package> ...
  7393. Upgrades one or more PEAR packages.  See documentation for the
  7394. "install" command for ways to specify a package.
  7395.  
  7396. When upgrading, your package will be updated if the provided new
  7397. package has a higher version number (use the -f option if you need to
  7398. upgrade anyway).
  7399.  
  7400. More than one package may be specified at once.
  7401. '),
  7402.         'upgrade-all' => array(
  7403.             'summary' => 'Upgrade All Packages',
  7404.             'function' => 'doUpgradeAll',
  7405.             'shortcut' => 'ua',
  7406.             'options' => array(
  7407.                 'nodeps' => array(
  7408.                     'shortopt' => 'n',
  7409.                     'doc' => 'ignore dependencies, upgrade anyway',
  7410.                     ),
  7411.                 'register-only' => array(
  7412.                     'shortopt' => 'r',
  7413.                     'doc' => 'do not install files, only register the package as upgraded',
  7414.                     ),
  7415.                 'nobuild' => array(
  7416.                     'shortopt' => 'B',
  7417.                     'doc' => 'don\'t build C extensions',
  7418.                     ),
  7419.                 'nocompress' => array(
  7420.                     'shortopt' => 'Z',
  7421.                     'doc' => 'request uncompressed files when downloading',
  7422.                     ),
  7423.                 'installroot' => array(
  7424.                     'shortopt' => 'R',
  7425.                     'arg' => 'DIR',
  7426.                     'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM',
  7427.                     ),
  7428.                 'ignore-errors' => array(
  7429.                     'doc' => 'force install even if there were errors',
  7430.                     ),
  7431.                 'loose' => array(
  7432.                     'doc' => 'do not check for recommended dependency version',
  7433.                     ),
  7434.                 ),
  7435.             'doc' => '
  7436. Upgrades all packages that have a newer release available.  Upgrades are
  7437. done only if there is a release available of the state specified in
  7438. "preferred_state" (currently {config preferred_state}), or a state considered
  7439. more stable.
  7440. '),
  7441.         'uninstall' => array(
  7442.             'summary' => 'Un-install Package',
  7443.             'function' => 'doUninstall',
  7444.             'shortcut' => 'un',
  7445.             'options' => array(
  7446.                 'nodeps' => array(
  7447.                     'shortopt' => 'n',
  7448.                     'doc' => 'ignore dependencies, uninstall anyway',
  7449.                     ),
  7450.                 'register-only' => array(
  7451.                     'shortopt' => 'r',
  7452.                     'doc' => 'do not remove files, only register the packages as not installed',
  7453.                     ),
  7454.                 'installroot' => array(
  7455.                     'shortopt' => 'R',
  7456.                     'arg' => 'DIR',
  7457.                     'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)',
  7458.                     ),
  7459.                 'ignore-errors' => array(
  7460.                     'doc' => 'force install even if there were errors',
  7461.                     ),
  7462.                 'offline' => array(
  7463.                     'shortopt' => 'O',
  7464.                     'doc' => 'do not attempt to uninstall remotely',
  7465.                     ),
  7466.                 ),
  7467.             'doc' => '[channel/]<package> ...
  7468. Uninstalls one or more PEAR packages.  More than one package may be
  7469. specified at once.  Prefix with channel name to uninstall from a
  7470. channel not in your default channel ({config default_channel})
  7471. '),
  7472.         'bundle' => array(
  7473.             'summary' => 'Unpacks a Pecl Package',
  7474.             'function' => 'doBundle',
  7475.             'shortcut' => 'bun',
  7476.             'options' => array(
  7477.                 'destination' => array(
  7478.                    'shortopt' => 'd',
  7479.                     'arg' => 'DIR',
  7480.                     'doc' => 'Optional destination directory for unpacking (defaults to current path or "ext" if exists)',
  7481.                     ),
  7482.                 'force' => array(
  7483.                     'shortopt' => 'f',
  7484.                     'doc' => 'Force the unpacking even if there were errors in the package',
  7485.                 ),
  7486.             ),
  7487.             'doc' => '<package>
  7488. Unpacks a Pecl Package into the selected location. It will download the
  7489. package if needed.
  7490. '),
  7491.         'run-scripts' => array(
  7492.             'summary' => 'Run Post-Install Scripts bundled with a package',
  7493.             'function' => 'doRunScripts',
  7494.             'shortcut' => 'rs',
  7495.             'options' => array(
  7496.             ),
  7497.             'doc' => '<package>
  7498. Run post-installation scripts in package <package>, if any exist.
  7499. '),
  7500.     );
  7501.  
  7502.     // }}}
  7503.     // {{{ constructor
  7504.  
  7505.     /**
  7506.      * PEAR_Command_Install constructor.
  7507.      *
  7508.      * @access public
  7509.      */
  7510.     function PEAR_Command_Install(&$ui, &$config)
  7511.     {
  7512.         parent::PEAR_Command_Common($ui, $config);
  7513.     }
  7514.  
  7515.     // }}}
  7516.  
  7517.     /**
  7518.      * For unit testing purposes
  7519.      */
  7520.     function &getDownloader(&$ui, $options, &$config)
  7521.     {
  7522.         if (!class_exists('PEAR_Downloader')) {
  7523.             require_once 'phar://go-pear.phar/' . 'PEAR/Downloader.php';
  7524.         }
  7525.         $a = &new PEAR_Downloader($ui, $options, $config);
  7526.         return $a;
  7527.     }
  7528.  
  7529.     /**
  7530.      * For unit testing purposes
  7531.      */
  7532.     function &getInstaller(&$ui)
  7533.     {
  7534.         if (!class_exists('PEAR_Installer')) {
  7535.             require_once 'phar://go-pear.phar/' . 'PEAR/Installer.php';
  7536.         }
  7537.         $a = &new PEAR_Installer($ui);
  7538.         return $a;
  7539.     }
  7540.  
  7541.     function enableExtension($binaries, $type)
  7542.     {
  7543.         if (!($phpini = $this->config->get('php_ini', null, 'pear.php.net'))) {
  7544.             return PEAR::raiseError('configuration option "php_ini" is not set to php.ini location');
  7545.         }
  7546.         $ini = $this->_parseIni($phpini);
  7547.         if (PEAR::isError($ini)) {
  7548.             return $ini;
  7549.         }
  7550.         $line = 0;
  7551.         if ($type == 'extsrc' || $type == 'extbin') {
  7552.             $search = 'extensions';
  7553.             $enable = 'extension';
  7554.         } else {
  7555.             $search = 'zend_extensions';
  7556.             ob_start();
  7557.             phpinfo(INFO_GENERAL);
  7558.             $info = ob_get_contents();
  7559.             ob_end_clean();
  7560.             $debug = function_exists('leak') ? '_debug' : '';
  7561.             $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : '';
  7562.             $enable = 'zend_extension' . $debug . $ts;
  7563.         }
  7564.         foreach ($ini[$search] as $line => $extension) {
  7565.             if (in_array($extension, $binaries, true) || in_array(
  7566.                   $ini['extension_dir'] . DIRECTORY_SEPARATOR . $extension, $binaries, true)) {
  7567.                 // already enabled - assume if one is, all are
  7568.                 return true;
  7569.             }
  7570.         }
  7571.         if ($line) {
  7572.             $newini = array_slice($ini['all'], 0, $line);
  7573.         } else {
  7574.             $newini = array();
  7575.         }
  7576.         foreach ($binaries as $binary) {
  7577.             if ($ini['extension_dir']) {
  7578.                 $binary = basename($binary);
  7579.             }
  7580.             $newini[] = $enable . '="' . $binary . '"' . (OS_UNIX ? "\n" : "\r\n");
  7581.         }
  7582.         $newini = array_merge($newini, array_slice($ini['all'], $line));
  7583.         $fp = @fopen($phpini, 'wb');
  7584.         if (!$fp) {
  7585.             return PEAR::raiseError('cannot open php.ini "' . $phpini . '" for writing');
  7586.         }
  7587.         foreach ($newini as $line) {
  7588.             fwrite($fp, $line);
  7589.         }
  7590.         fclose($fp);
  7591.         return true;
  7592.     }
  7593.  
  7594.     function disableExtension($binaries, $type)
  7595.     {
  7596.         if (!($phpini = $this->config->get('php_ini', null, 'pear.php.net'))) {
  7597.             return PEAR::raiseError('configuration option "php_ini" is not set to php.ini location');
  7598.         }
  7599.         $ini = $this->_parseIni($phpini);
  7600.         if (PEAR::isError($ini)) {
  7601.             return $ini;
  7602.         }
  7603.         $line = 0;
  7604.         if ($type == 'extsrc' || $type == 'extbin') {
  7605.             $search = 'extensions';
  7606.             $enable = 'extension';
  7607.         } else {
  7608.             $search = 'zend_extensions';
  7609.             ob_start();
  7610.             phpinfo(INFO_GENERAL);
  7611.             $info = ob_get_contents();
  7612.             ob_end_clean();
  7613.             $debug = function_exists('leak') ? '_debug' : '';
  7614.             $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : '';
  7615.             $enable = 'zend_extension' . $debug . $ts;
  7616.         }
  7617.         $found = false;
  7618.         foreach ($ini[$search] as $line => $extension) {
  7619.             if (in_array($extension, $binaries, true) || in_array(
  7620.                   $ini['extension_dir'] . DIRECTORY_SEPARATOR . $extension, $binaries, true)) {
  7621.                 $found = true;
  7622.                 break;
  7623.             }
  7624.         }
  7625.         if (!$found) {
  7626.             // not enabled
  7627.             return true;
  7628.         }
  7629.         $fp = @fopen($phpini, 'wb');
  7630.         if (!$fp) {
  7631.             return PEAR::raiseError('cannot open php.ini "' . $phpini . '" for writing');
  7632.         }
  7633.         if ($line) {
  7634.             $newini = array_slice($ini['all'], 0, $line);
  7635.             // delete the enable line
  7636.             $newini = array_merge($newini, array_slice($ini['all'], $line + 1));
  7637.         } else {
  7638.             $newini = array_slice($ini['all'], 1);
  7639.         }
  7640.         foreach ($newini as $line) {
  7641.             fwrite($fp, $line);
  7642.         }
  7643.         fclose($fp);
  7644.         return true;
  7645.     }
  7646.  
  7647.     function _parseIni($filename)
  7648.     {
  7649.         if (file_exists($filename)) {
  7650.             if (filesize($filename) > 300000) {
  7651.                 return PEAR::raiseError('php.ini "' . $filename . '" is too large, aborting');
  7652.             }
  7653.             ob_start();
  7654.             phpinfo(INFO_GENERAL);
  7655.             $info = ob_get_contents();
  7656.             ob_end_clean();
  7657.             $debug = function_exists('leak') ? '_debug' : '';
  7658.             $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : '';
  7659.             $zend_extension_line = 'zend_extension' . $debug . $ts;
  7660.             $all = @file($filename);
  7661.             if (!$all) {
  7662.                 return PEAR::raiseError('php.ini "' . $filename .'" could not be read');
  7663.             }
  7664.             $zend_extensions = $extensions = array();
  7665.             // assume this is right, but pull from the php.ini if it is found
  7666.             $extension_dir = ini_get('extension_dir');
  7667.             foreach ($all as $linenum => $line) {
  7668.                 $line = trim($line);
  7669.                 if (!$line) {
  7670.                     continue;
  7671.                 }
  7672.                 if ($line[0] == ';') {
  7673.                     continue;
  7674.                 }
  7675.                 if (strtolower(substr($line, 0, 13)) == 'extension_dir') {
  7676.                     $line = trim(substr($line, 13));
  7677.                     if ($line[0] == '=') {
  7678.                         $x = trim(substr($line, 1));
  7679.                         $x = explode(';', $x);
  7680.                         $extension_dir = str_replace('"', '', array_shift($x));
  7681.                         continue;
  7682.                     }
  7683.                 }
  7684.                 if (strtolower(substr($line, 0, 9)) == 'extension') {
  7685.                     $line = trim(substr($line, 9));
  7686.                     if ($line[0] == '=') {
  7687.                         $x = trim(substr($line, 1));
  7688.                         $x = explode(';', $x);
  7689.                         $extensions[$linenum] = str_replace('"', '', array_shift($x));
  7690.                         continue;
  7691.                     }
  7692.                 }
  7693.                 if (strtolower(substr($line, 0, strlen($zend_extension_line))) ==
  7694.                       $zend_extension_line) {
  7695.                     $line = trim(substr($line, strlen($zend_extension_line)));
  7696.                     if ($line[0] == '=') {
  7697.                         $x = trim(substr($line, 1));
  7698.                         $x = explode(';', $x);
  7699.                         $zend_extensions[$linenum] = str_replace('"', '', array_shift($x));
  7700.                         continue;
  7701.                     }
  7702.                 }
  7703.             }
  7704.             return array(
  7705.                 'extensions' => $extensions,
  7706.                 'zend_extensions' => $zend_extensions,
  7707.                 'extension_dir' => $extension_dir,
  7708.                 'all' => $all,
  7709.             );
  7710.         } else {
  7711.             return PEAR::raiseError('php.ini "' . $filename . '" does not exist');
  7712.         }
  7713.     }
  7714.  
  7715.     // {{{ doInstall()
  7716.  
  7717.     function doInstall($command, $options, $params)
  7718.     {
  7719.         if (!class_exists('PEAR_PackageFile')) {
  7720.             require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile.php';
  7721.         }
  7722.         if (empty($this->installer)) {
  7723.             $this->installer = &$this->getInstaller($this->ui);
  7724.         }
  7725.         if ($command == 'upgrade' || $command == 'upgrade-all') {
  7726.             $options['upgrade'] = true;
  7727.         } else {
  7728.             $packages = $params;
  7729.         }
  7730.         if (isset($options['installroot']) && isset($options['packagingroot'])) {
  7731.             return $this->raiseError('ERROR: cannot use both --installroot and --packagingroot');
  7732.         }
  7733.         $reg = &$this->config->getRegistry();
  7734.         $instreg = &$reg; // instreg used to check if package is installed
  7735.         if (isset($options['packagingroot']) && !isset($options['upgrade'])) {
  7736.             $packrootphp_dir = $this->installer->_prependPath(
  7737.                 $this->config->get('php_dir', null, 'pear.php.net'),
  7738.                 $options['packagingroot']);
  7739.             $instreg = new PEAR_Registry($packrootphp_dir); // other instreg!
  7740.  
  7741.             if ($this->config->get('verbose') > 2) {
  7742.                 $this->ui->outputData('using package root: ' . $options['packagingroot']);
  7743.             }
  7744.         }
  7745.         $abstractpackages = array();
  7746.         $otherpackages = array();
  7747.         // parse params
  7748.         PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  7749.         foreach($params as $param) {
  7750.             if (strpos($param, 'http://') === 0) {
  7751.                 $otherpackages[] = $param;
  7752.                 continue;
  7753.             }
  7754.             if (strpos($param, 'channel://') === false && @file_exists($param)) {
  7755.                 if (isset($options['force'])) {
  7756.                     $otherpackages[] = $param;
  7757.                     continue;
  7758.                 }
  7759.                 $pkg = new PEAR_PackageFile($this->config);
  7760.                 $pf = $pkg->fromAnyFile($param, PEAR_VALIDATE_DOWNLOADING);
  7761.                 if (PEAR::isError($pf)) {
  7762.                     $otherpackages[] = $param;
  7763.                     continue;
  7764.                 }
  7765.                 if ($reg->packageExists($pf->getPackage(), $pf->getChannel()) &&
  7766.                       version_compare($pf->getVersion(),
  7767.                       $reg->packageInfo($pf->getPackage(), 'version', $pf->getChannel()),
  7768.                       '<=')) {
  7769.                     if ($this->config->get('verbose')) {
  7770.                         $this->ui->outputData('Ignoring installed package ' .
  7771.                             $reg->parsedPackageNameToString(
  7772.                             array('package' => $pf->getPackage(),
  7773.                                   'channel' => $pf->getChannel()), true));
  7774.                     }
  7775.                     continue;
  7776.                 }
  7777.                 $otherpackages[] = $param;
  7778.                 continue;
  7779.             }
  7780.             $e = $reg->parsePackageName($param, $this->config->get('default_channel'));
  7781.             if (PEAR::isError($e)) {
  7782.                 $otherpackages[] = $param;
  7783.             } else {
  7784.                 $abstractpackages[] = $e;
  7785.             }
  7786.         }
  7787.         PEAR::staticPopErrorHandling();
  7788.  
  7789.         // if there are any local package .tgz or remote static url, we can't
  7790.         // filter.  The filter only works for abstract packages
  7791.         if (count($abstractpackages) && !isset($options['force'])) {
  7792.             // when not being forced, only do necessary upgrades/installs
  7793.             if (isset($options['upgrade'])) {
  7794.                 $abstractpackages = $this->_filterUptodatePackages($abstractpackages,
  7795.                     $command);
  7796.             } else {
  7797.                 foreach ($abstractpackages as $i => $package) {
  7798.                     if (isset($package['group'])) {
  7799.                         // do not filter out install groups
  7800.                         continue;
  7801.                     }
  7802.                     if ($instreg->packageExists($package['package'], $package['channel'])) {
  7803.                         if ($this->config->get('verbose')) {
  7804.                             $this->ui->outputData('Ignoring installed package ' .
  7805.                                 $reg->parsedPackageNameToString($package, true));
  7806.                         }
  7807.                         unset($abstractpackages[$i]);
  7808.                     }
  7809.                 }
  7810.             }
  7811.             $abstractpackages =
  7812.                 array_map(array($reg, 'parsedPackageNameToString'), $abstractpackages);
  7813.         } elseif (count($abstractpackages)) {
  7814.             $abstractpackages =
  7815.                 array_map(array($reg, 'parsedPackageNameToString'), $abstractpackages);
  7816.         }
  7817.  
  7818.  
  7819.         $packages = array_merge($abstractpackages, $otherpackages);
  7820.         if (!count($packages)) {
  7821.             $this->ui->outputData('Nothing to ' . $command);
  7822.             return true;
  7823.         }
  7824.  
  7825.         $this->downloader = &$this->getDownloader($this->ui, $options, $this->config);
  7826.         $errors = array();
  7827.         $binaries = array();
  7828.         $downloaded = array();
  7829.         $downloaded = &$this->downloader->download($packages);
  7830.         if (PEAR::isError($downloaded)) {
  7831.             return $this->raiseError($downloaded);
  7832.         }
  7833.         $errors = $this->downloader->getErrorMsgs();
  7834.         if (count($errors)) {
  7835.             $err = array();
  7836.             $err['data'] = array();
  7837.             foreach ($errors as $error) {
  7838.                 $err['data'][] = array($error);
  7839.             }
  7840.             $err['headline'] = 'Install Errors';
  7841.             $this->ui->outputData($err);
  7842.             if (!count($downloaded)) {
  7843.                 return $this->raiseError("$command failed");
  7844.             }
  7845.         }
  7846.         $data = array(
  7847.             'headline' => 'Packages that would be Installed'
  7848.         );
  7849.         if (isset($options['pretend'])) {
  7850.             foreach ($downloaded as $package) {
  7851.                 $data['data'][] = array($reg->parsedPackageNameToString($package->getParsedPackage()));
  7852.             }
  7853.             $this->ui->outputData($data, 'pretend');
  7854.             return true;
  7855.         }
  7856.         $this->installer->setOptions($options);
  7857.         $this->installer->sortPackagesForInstall($downloaded);
  7858.         if (PEAR::isError($err = $this->installer->setDownloadedPackages($downloaded))) {
  7859.             $this->raiseError($err->getMessage());
  7860.             return true;
  7861.         }
  7862.         $extrainfo = array();
  7863.         $binaries = array();
  7864.         foreach ($downloaded as $param) {
  7865.             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  7866.             $info = $this->installer->install($param, $options);
  7867.             PEAR::staticPopErrorHandling();
  7868.             if (PEAR::isError($info)) {
  7869.                 $oldinfo = $info;
  7870.                 $pkg = &$param->getPackageFile();
  7871.                 if ($info->getCode() != PEAR_INSTALLER_NOBINARY) {
  7872.                     if (!($info = $pkg->installBinary($this->installer))) {
  7873.                         $this->ui->outputData('ERROR: ' .$oldinfo->getMessage());
  7874.                         continue;
  7875.                     }
  7876.                     // we just installed a different package than requested,
  7877.                     // let's change the param and info so that the rest of this works
  7878.                     $param = $info[0];
  7879.                     $info = $info[1];
  7880.                 }
  7881.             }
  7882.             if (is_array($info)) {
  7883.                 if ($param->getPackageType() == 'extsrc' ||
  7884.                       $param->getPackageType() == 'extbin' ||
  7885.                       $param->getPackageType() == 'zendextsrc' ||
  7886.                       $param->getPackageType() == 'zendextbin') {
  7887.                     $pkg = &$param->getPackageFile();
  7888.                     if ($instbin = $pkg->getInstalledBinary()) {
  7889.                         $instpkg = &$instreg->getPackage($instbin, $pkg->getChannel());
  7890.                     } else {
  7891.                         $instpkg = &$instreg->getPackage($pkg->getPackage(), $pkg->getChannel());
  7892.                     }
  7893.  
  7894.                     foreach ($instpkg->getFilelist() as $name => $atts) {
  7895.                         $pinfo = pathinfo($atts['installed_as']);
  7896.                         if (!isset($pinfo['extension']) ||
  7897.                               in_array($pinfo['extension'], array('c', 'h'))) {
  7898.                             continue; // make sure we don't match php_blah.h
  7899.                         }
  7900.                         if ((strpos($pinfo['basename'], 'php_') === 0 &&
  7901.                               $pinfo['extension'] == 'dll') ||
  7902.                               // most unices
  7903.                               $pinfo['extension'] == 'so' ||
  7904.                               // hp-ux
  7905.                               $pinfo['extension'] == 'sl') {
  7906.                             $binaries[] = array($atts['installed_as'], $pinfo);
  7907.                             break;
  7908.                         }
  7909.                     }
  7910.                     if (count($binaries)) {
  7911.                         foreach ($binaries as $pinfo) {
  7912.                             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  7913.                             $ret = $this->enableExtension(array($pinfo[0]), $param->getPackageType());
  7914.                             PEAR::staticPopErrorHandling();
  7915.                             if (PEAR::isError($ret)) {
  7916.                                 $extrainfo[] = $ret->getMessage();
  7917.                                 if ($param->getPackageType() == 'extsrc' ||
  7918.                                       $param->getPackageType() == 'extbin') {
  7919.                                     $exttype = 'extension';
  7920.                                 } else {
  7921.                                     ob_start();
  7922.                                     phpinfo(INFO_GENERAL);
  7923.                                     $info = ob_get_contents();
  7924.                                     ob_end_clean();
  7925.                                     $debug = function_exists('leak') ? '_debug' : '';
  7926.                                     $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : '';
  7927.                                     $exttype = 'zend_extension' . $debug . $ts;
  7928.                                 }
  7929.                                 $extrainfo[] = 'You should add "' . $exttype . '=' .
  7930.                                     $pinfo[1]['basename'] . '" to php.ini';
  7931.                             } else {
  7932.                                 $extrainfo[] = 'Extension ' . $instpkg->getProvidesExtension() .
  7933.                                     ' enabled in php.ini';
  7934.                             }
  7935.                         }
  7936.                     }
  7937.                 }
  7938.                 if ($this->config->get('verbose') > 0) {
  7939.                     $channel = $param->getChannel();
  7940.                     $label = $reg->parsedPackageNameToString(
  7941.                         array(
  7942.                             'channel' => $channel,
  7943.                             'package' => $param->getPackage(),
  7944.                             'version' => $param->getVersion(),
  7945.                         ));
  7946.                     $out = array('data' => "$command ok: $label");
  7947.                     if (isset($info['release_warnings'])) {
  7948.                         $out['release_warnings'] = $info['release_warnings'];
  7949.                     }
  7950.                     $this->ui->outputData($out, $command);
  7951.                     if (!isset($options['register-only']) && !isset($options['offline'])) {
  7952.                         if ($this->config->isDefinedLayer('ftp')) {
  7953.                             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  7954.                             $info = $this->installer->ftpInstall($param);
  7955.                             PEAR::staticPopErrorHandling();
  7956.                             if (PEAR::isError($info)) {
  7957.                                 $this->ui->outputData($info->getMessage());
  7958.                                 $this->ui->outputData("remote install failed: $label");
  7959.                             } else {
  7960.                                 $this->ui->outputData("remote install ok: $label");
  7961.                             }
  7962.                         }
  7963.                     }
  7964.                 }
  7965.                 $deps = $param->getDeps();
  7966.                 if ($deps) {
  7967.                     if (isset($deps['group'])) {
  7968.                         $groups = $deps['group'];
  7969.                         if (!isset($groups[0])) {
  7970.                             $groups = array($groups);
  7971.                         }
  7972.                         foreach ($groups as $group) {
  7973.                             if ($group['attribs']['name'] == 'default') {
  7974.                                 // default group is always installed, unless the user
  7975.                                 // explicitly chooses to install another group
  7976.                                 continue;
  7977.                             }
  7978.                             $extrainfo[] = $param->getPackage() . ': Optional feature ' .
  7979.                                 $group['attribs']['name'] . ' available (' .
  7980.                                 $group['attribs']['hint'] . ')';
  7981.                         }
  7982.                         $extrainfo[] = $param->getPackage() .
  7983.                             ': To install optional features use "pear install ' .
  7984.                             $reg->parsedPackageNameToString(
  7985.                                 array('package' => $param->getPackage(),
  7986.                                       'channel' => $param->getChannel()), true) .
  7987.                                   '#featurename"';
  7988.                     }
  7989.                 }
  7990.                 $pkg = &$instreg->getPackage($param->getPackage(), $param->getChannel());
  7991.                 // $pkg may be NULL if install is a 'fake' install via --packagingroot
  7992.                 if (is_object($pkg)) {
  7993.                     $pkg->setConfig($this->config);
  7994.                     if ($list = $pkg->listPostinstallScripts()) {
  7995.                         $pn = $reg->parsedPackageNameToString(array('channel' =>
  7996.                            $param->getChannel(), 'package' => $param->getPackage()), true);
  7997.                         $extrainfo[] = $pn . ' has post-install scripts:';
  7998.                         foreach ($list as $file) {
  7999.                             $extrainfo[] = $file;
  8000.                         }
  8001.                         $extrainfo[] = $param->getPackage() .
  8002.                             ': Use "pear run-scripts ' . $pn . '" to finish setup.';
  8003.                         $extrainfo[] = 'DO NOT RUN SCRIPTS FROM UNTRUSTED SOURCES';
  8004.                     }
  8005.                 }
  8006.             } else {
  8007.                 return $this->raiseError("$command failed");
  8008.             }
  8009.         }
  8010.         if (count($extrainfo)) {
  8011.             foreach ($extrainfo as $info) {
  8012.                 $this->ui->outputData($info);
  8013.             }
  8014.         }
  8015.         return true;
  8016.     }
  8017.  
  8018.     // }}}
  8019.     // {{{ doUpgradeAll()
  8020.  
  8021.     function doUpgradeAll($command, $options, $params)
  8022.     {
  8023.         $reg = &$this->config->getRegistry();
  8024.         $toUpgrade = array();
  8025.         foreach ($reg->listChannels() as $channel) {
  8026.             if ($channel == '__uri') {
  8027.                 continue;
  8028.             }
  8029.  
  8030.             // parse name with channel
  8031.             foreach ($reg->listPackages($channel) as $name) {
  8032.                 $toUpgrade[] = $reg->parsedPackageNameToString(array(
  8033.                         'channel' => $channel,
  8034.                         'package' => $name
  8035.                     ));
  8036.             }
  8037.         }
  8038.  
  8039.         $err = $this->doInstall('upgrade-all', $options, $toUpgrade);
  8040.         if (PEAR::isError($err)) {
  8041.             $this->ui->outputData($err->getMessage(), $command);
  8042.         }
  8043.    }
  8044.  
  8045.     // }}}
  8046.     // {{{ doUninstall()
  8047.  
  8048.     function doUninstall($command, $options, $params)
  8049.     {
  8050.         if (empty($this->installer)) {
  8051.             $this->installer = &$this->getInstaller($this->ui);
  8052.         }
  8053.         if (isset($options['remoteconfig'])) {
  8054.             $e = $this->config->readFTPConfigFile($options['remoteconfig']);
  8055.             if (!PEAR::isError($e)) {
  8056.                 $this->installer->setConfig($this->config);
  8057.             }
  8058.         }
  8059.         if (sizeof($params) < 1) {
  8060.             return $this->raiseError("Please supply the package(s) you want to uninstall");
  8061.         }
  8062.         $reg = &$this->config->getRegistry();
  8063.         $newparams = array();
  8064.         $binaries = array();
  8065.         $badparams = array();
  8066.         foreach ($params as $pkg) {
  8067.             $channel = $this->config->get('default_channel');
  8068.             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  8069.             $parsed = $reg->parsePackageName($pkg, $channel);
  8070.             PEAR::staticPopErrorHandling();
  8071.             if (!$parsed || PEAR::isError($parsed)) {
  8072.                 $badparams[] = $pkg;
  8073.                 continue;
  8074.             }
  8075.             $package = $parsed['package'];
  8076.             $channel = $parsed['channel'];
  8077.             $info = &$reg->getPackage($package, $channel);
  8078.             if ($info === null &&
  8079.                  ($channel == 'pear.php.net' || $channel == 'pecl.php.net')) {
  8080.                 // make sure this isn't a package that has flipped from pear to pecl but
  8081.                 // used a package.xml 1.0
  8082.                 $testc = ($channel == 'pear.php.net') ? 'pecl.php.net' : 'pear.php.net';
  8083.                 $info = &$reg->getPackage($package, $testc);
  8084.                 if ($info !== null) {
  8085.                     $channel = $testc;
  8086.                 }
  8087.             }
  8088.             if ($info === null) {
  8089.                 $badparams[] = $pkg;
  8090.             } else {
  8091.                 $newparams[] = &$info;
  8092.                 // check for binary packages (this is an alias for those packages if so)
  8093.                 if ($installedbinary = $info->getInstalledBinary()) {
  8094.                     $this->ui->log('adding binary package ' .
  8095.                         $reg->parsedPackageNameToString(array('channel' => $channel,
  8096.                             'package' => $installedbinary), true));
  8097.                     $newparams[] = &$reg->getPackage($installedbinary, $channel);
  8098.                 }
  8099.                 // add the contents of a dependency group to the list of installed packages
  8100.                 if (isset($parsed['group'])) {
  8101.                     $group = $info->getDependencyGroup($parsed['group']);
  8102.                     if ($group) {
  8103.                         $installed = &$reg->getInstalledGroup($group);
  8104.                         if ($installed) {
  8105.                             foreach ($installed as $i => $p) {
  8106.                                 $newparams[] = &$installed[$i];
  8107.                             }
  8108.                         }
  8109.                     }
  8110.                 }
  8111.             }
  8112.         }
  8113.         $err = $this->installer->sortPackagesForUninstall($newparams);
  8114.         if (PEAR::isError($err)) {
  8115.             $this->ui->outputData($err->getMessage(), $command);
  8116.             return true;
  8117.         }
  8118.         $params = $newparams;
  8119.         // twist this to use it to check on whether dependent packages are also being uninstalled
  8120.         // for circular dependencies like subpackages
  8121.         $this->installer->setUninstallPackages($newparams);
  8122.         $params = array_merge($params, $badparams);
  8123.         $binaries = array();
  8124.         foreach ($params as $pkg) {
  8125.             $this->installer->pushErrorHandling(PEAR_ERROR_RETURN);
  8126.             if ($err = $this->installer->uninstall($pkg, $options)) {
  8127.                 $this->installer->popErrorHandling();
  8128.                 if (PEAR::isError($err)) {
  8129.                     $this->ui->outputData($err->getMessage(), $command);
  8130.                     continue;
  8131.                 }
  8132.                 if ($pkg->getPackageType() == 'extsrc' ||
  8133.                       $pkg->getPackageType() == 'extbin' ||
  8134.                       $pkg->getPackageType() == 'zendextsrc' ||
  8135.                       $pkg->getPackageType() == 'zendextbin') {
  8136.                     if ($instbin = $pkg->getInstalledBinary()) {
  8137.                         continue; // this will be uninstalled later
  8138.                     }
  8139.  
  8140.                     foreach ($pkg->getFilelist() as $name => $atts) {
  8141.                         $pinfo = pathinfo($atts['installed_as']);
  8142.                         if (!isset($pinfo['extension']) ||
  8143.                               in_array($pinfo['extension'], array('c', 'h'))) {
  8144.                             continue; // make sure we don't match php_blah.h
  8145.                         }
  8146.                         if ((strpos($pinfo['basename'], 'php_') === 0 &&
  8147.                               $pinfo['extension'] == 'dll') ||
  8148.                               // most unices
  8149.                               $pinfo['extension'] == 'so' ||
  8150.                               // hp-ux
  8151.                               $pinfo['extension'] == 'sl') {
  8152.                             $binaries[] = array($atts['installed_as'], $pinfo);
  8153.                             break;
  8154.                         }
  8155.                     }
  8156.                     if (count($binaries)) {
  8157.                         foreach ($binaries as $pinfo) {
  8158.                             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  8159.                             $ret = $this->disableExtension(array($pinfo[0]), $pkg->getPackageType());
  8160.                             PEAR::staticPopErrorHandling();
  8161.                             if (PEAR::isError($ret)) {
  8162.                                 $extrainfo[] = $ret->getMessage();
  8163.                                 if ($pkg->getPackageType() == 'extsrc' ||
  8164.                                       $pkg->getPackageType() == 'extbin') {
  8165.                                     $exttype = 'extension';
  8166.                                 } else {
  8167.                                     ob_start();
  8168.                                     phpinfo(INFO_GENERAL);
  8169.                                     $info = ob_get_contents();
  8170.                                     ob_end_clean();
  8171.                                     $debug = function_exists('leak') ? '_debug' : '';
  8172.                                     $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : '';
  8173.                                     $exttype = 'zend_extension' . $debug . $ts;
  8174.                                 }
  8175.                                 $this->ui->outputData('Unable to remove "' . $exttype . '=' .
  8176.                                     $pinfo[1]['basename'] . '" from php.ini', $command);
  8177.                             } else {
  8178.                                 $this->ui->outputData('Extension ' . $pkg->getProvidesExtension() .
  8179.                                     ' disabled in php.ini', $command);
  8180.                             }
  8181.                         }
  8182.                     }
  8183.                 }
  8184.                 $savepkg = $pkg;
  8185.                 if ($this->config->get('verbose') > 0) {
  8186.                     if (is_object($pkg)) {
  8187.                         $pkg = $reg->parsedPackageNameToString($pkg);
  8188.                     }
  8189.                     $this->ui->outputData("uninstall ok: $pkg", $command);
  8190.                 }
  8191.                 if (!isset($options['offline']) && is_object($savepkg) &&
  8192.                       defined('PEAR_REMOTEINSTALL_OK')) {
  8193.                     if ($this->config->isDefinedLayer('ftp')) {
  8194.                         $this->installer->pushErrorHandling(PEAR_ERROR_RETURN);
  8195.                         $info = $this->installer->ftpUninstall($savepkg);
  8196.                         $this->installer->popErrorHandling();
  8197.                         if (PEAR::isError($info)) {
  8198.                             $this->ui->outputData($info->getMessage());
  8199.                             $this->ui->outputData("remote uninstall failed: $pkg");
  8200.                         } else {
  8201.                             $this->ui->outputData("remote uninstall ok: $pkg");
  8202.                         }
  8203.                     }
  8204.                 }
  8205.             } else {
  8206.                 $this->installer->popErrorHandling();
  8207.                 if (is_object($pkg)) {
  8208.                     $pkg = $reg->parsedPackageNameToString($pkg);
  8209.                 }
  8210.                 return $this->raiseError("uninstall failed: $pkg");
  8211.             }
  8212.         }
  8213.         return true;
  8214.     }
  8215.  
  8216.     // }}}
  8217.  
  8218.  
  8219.     // }}}
  8220.     // {{{ doBundle()
  8221.     /*
  8222.     (cox) It just downloads and untars the package, does not do
  8223.             any check that the PEAR_Installer::_installFile() does.
  8224.     */
  8225.  
  8226.     function doBundle($command, $options, $params)
  8227.     {
  8228.         $downloader = &$this->getDownloader($this->ui, array('force' => true, 'nodeps' => true,
  8229.             'soft' => true, 'downloadonly' => true), $this->config);
  8230.         $reg = &$this->config->getRegistry();
  8231.         if (sizeof($params) < 1) {
  8232.             return $this->raiseError("Please supply the package you want to bundle");
  8233.         }
  8234.  
  8235.         if (isset($options['destination'])) {
  8236.             if (!is_dir($options['destination'])) {
  8237.                 System::mkdir('-p ' . $options['destination']);
  8238.             }
  8239.             $dest = realpath($options['destination']);
  8240.         } else {
  8241.             $pwd = getcwd();
  8242.             if (is_dir($pwd . DIRECTORY_SEPARATOR . 'ext')) {
  8243.                 $dest = $pwd . DIRECTORY_SEPARATOR . 'ext';
  8244.             } else {
  8245.                 $dest = $pwd;
  8246.             }
  8247.         }
  8248.         PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  8249.         $err = $downloader->setDownloadDir($dest);
  8250.         PEAR::staticPopErrorHandling();
  8251.         if (PEAR::isError($err)) {
  8252.             return PEAR::raiseError('download directory "' . $dest .
  8253.                 '" is not writeable.');
  8254.         }
  8255.         $result = &$downloader->download(array($params[0]));
  8256.         if (PEAR::isError($result)) {
  8257.             return $result;
  8258.         }
  8259.         if (!isset($result[0])) {
  8260.             return $this->raiseError('unable to unpack ' . $params[0]);
  8261.         }
  8262.         $pkgfile = &$result[0]->getPackageFile();
  8263.         $pkgname = $pkgfile->getName();
  8264.         $pkgversion = $pkgfile->getVersion();
  8265.  
  8266.         // Unpacking -------------------------------------------------
  8267.         $dest .= DIRECTORY_SEPARATOR . $pkgname;
  8268.         $orig = $pkgname . '-' . $pkgversion;
  8269.  
  8270.         $tar = &new Archive_Tar($pkgfile->getArchiveFile());
  8271.         if (!$tar->extractModify($dest, $orig)) {
  8272.             return $this->raiseError('unable to unpack ' . $pkgfile->getArchiveFile());
  8273.         }
  8274.         $this->ui->outputData("Package ready at '$dest'");
  8275.     // }}}
  8276.     }
  8277.  
  8278.     // }}}
  8279.  
  8280.     function doRunScripts($command, $options, $params)
  8281.     {
  8282.         if (!isset($params[0])) {
  8283.             return $this->raiseError('run-scripts expects 1 parameter: a package name');
  8284.         }
  8285.         $reg = &$this->config->getRegistry();
  8286.         PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  8287.         $parsed = $reg->parsePackageName($params[0], $this->config->get('default_channel'));
  8288.         PEAR::staticPopErrorHandling();
  8289.         if (PEAR::isError($parsed)) {
  8290.             return $this->raiseError($parsed);
  8291.         }
  8292.         $package = &$reg->getPackage($parsed['package'], $parsed['channel']);
  8293.         if (is_object($package)) {
  8294.             $package->setConfig($this->config);
  8295.             $package->runPostinstallScripts();
  8296.         } else {
  8297.             return $this->raiseError('Could not retrieve package "' . $params[0] . '" from registry');
  8298.         }
  8299.         $this->ui->outputData('Install scripts complete', $command);
  8300.         return true;
  8301.     }
  8302.  
  8303.     /**
  8304.      * Given a list of packages, filter out those ones that are already up to date
  8305.      *
  8306.      * @param $packages: packages, in parsed array format !
  8307.      * @return list of packages that can be upgraded
  8308.      */
  8309.     function _filterUptodatePackages($packages, $command)
  8310.     {
  8311.         $reg = &$this->config->getRegistry();
  8312.         $latestReleases = array();
  8313.  
  8314.         $ret = array();
  8315.         foreach($packages as $package) {
  8316.             if (isset($package['group'])) {
  8317.                 $ret[] = $package;
  8318.                 continue;
  8319.             }
  8320.             $channel = $package['channel'];
  8321.             $name = $package['package'];
  8322.  
  8323.             if (!$reg->packageExists($name, $channel)) {
  8324.                 $ret[] = $package;
  8325.                 continue;
  8326.             }
  8327.             if (!isset($latestReleases[$channel])) {
  8328.                 // fill in cache for this channel
  8329.                 $chan = &$reg->getChannel($channel);
  8330.                 if (PEAR::isError($chan)) {
  8331.                     return $this->raiseError($chan);
  8332.                 }
  8333.                 if ($chan->supportsREST($this->config->get('preferred_mirror',
  8334.                                                            null, $channel)) &&
  8335.                       $base = $chan->getBaseURL('REST1.0',
  8336.                                                 $this->config->get('preferred_mirror',
  8337.                                                                    null, $channel)))
  8338.                 {
  8339.                     $dorest = true;
  8340.                 } else {
  8341.                     $dorest = false;
  8342.                     $remote = &$this->config->getRemote($this->config);
  8343.                 }
  8344.                 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  8345.                 if ($dorest) {
  8346.                     $rest = &$this->config->getREST('1.0', array());
  8347.                     $installed = array_flip($reg->listPackages($channel));
  8348.                     $latest = $rest->listLatestUpgrades($base,
  8349.                         $this->config->get('preferred_state', null, $channel), $installed,
  8350.                         $channel, $reg);
  8351.                 } else {
  8352.                     $latest = $remote->call("package.listLatestReleases",
  8353.                         $this->config->get('preferred_state', null, $channel));
  8354.                     unset($remote);
  8355.                 }
  8356.                 PEAR::staticPopErrorHandling();
  8357.                 if (PEAR::isError($latest)) {
  8358.                     $this->ui->outputData('Error getting channel info from ' . $channel .
  8359.                         ': ' . $latest->getMessage());
  8360.                     continue;
  8361.                 }
  8362.  
  8363.                 $latestReleases[$channel] = array_change_key_case($latest);
  8364.             }
  8365.  
  8366.             // check package for latest release
  8367.             if (isset($latestReleases[$channel][strtolower($name)])) {
  8368.                 // if not set, up to date
  8369.                 $inst_version = $reg->packageInfo($name, 'version', $channel);
  8370.                 $channel_version = $latestReleases[$channel][strtolower($name)]['version'];
  8371.                 if (version_compare($channel_version, $inst_version, "le")) {
  8372.                     // installed version is up-to-date
  8373.                     continue;
  8374.                 }
  8375.                 // maintain BC
  8376.                 if ($command == 'upgrade-all') {
  8377.                     $this->ui->outputData(array('data' => 'Will upgrade ' .
  8378.                         $reg->parsedPackageNameToString($package)), $command);
  8379.                 }
  8380.                 $ret[] = $package;
  8381.             }
  8382.         }
  8383.  
  8384.         return $ret;
  8385.     }
  8386.  
  8387. }
  8388. ?>
  8389. <commands version="1.0">
  8390.  <install>
  8391.   <summary>Install Package</summary>
  8392.   <function>doInstall</function>
  8393.   <shortcut>i</shortcut>
  8394.   <options>
  8395.    <force>
  8396.     <shortopt>f</shortopt>
  8397.     <doc>will overwrite newer installed packages</doc>
  8398.    </force>
  8399.    <loose>
  8400.     <shortopt>l</shortopt>
  8401.     <doc>do not check for recommended dependency version</doc>
  8402.    </loose>
  8403.    <nodeps>
  8404.     <shortopt>n</shortopt>
  8405.     <doc>ignore dependencies, install anyway</doc>
  8406.    </nodeps>
  8407.    <register-only>
  8408.     <shortopt>r</shortopt>
  8409.     <doc>do not install files, only register the package as installed</doc>
  8410.    </register-only>
  8411.    <soft>
  8412.     <shortopt>s</shortopt>
  8413.     <doc>soft install, fail silently, or upgrade if already installed</doc>
  8414.    </soft>
  8415.    <nobuild>
  8416.     <shortopt>B</shortopt>
  8417.     <doc>don't build C extensions</doc>
  8418.    </nobuild>
  8419.    <nocompress>
  8420.     <shortopt>Z</shortopt>
  8421.     <doc>request uncompressed files when downloading</doc>
  8422.    </nocompress>
  8423.    <installroot>
  8424.     <shortopt>R</shortopt>
  8425.     <arg>DIR</arg>
  8426.     <doc>root directory used when installing files (ala PHP's INSTALL_ROOT), use packagingroot for RPM</doc>
  8427.    </installroot>
  8428.    <packagingroot>
  8429.     <shortopt>P</shortopt>
  8430.     <arg>DIR</arg>
  8431.     <doc>root directory used when packaging files, like RPM packaging</doc>
  8432.    </packagingroot>
  8433.    <ignore-errors>
  8434.     <doc>force install even if there were errors</doc>
  8435.    </ignore-errors>
  8436.    <alldeps>
  8437.     <shortopt>a</shortopt>
  8438.     <doc>install all required and optional dependencies</doc>
  8439.    </alldeps>
  8440.    <onlyreqdeps>
  8441.     <shortopt>o</shortopt>
  8442.     <doc>install all required dependencies</doc>
  8443.    </onlyreqdeps>
  8444.    <offline>
  8445.     <shortopt>O</shortopt>
  8446.     <doc>do not attempt to download any urls or contact channels</doc>
  8447.    </offline>
  8448.    <pretend>
  8449.     <shortopt>p</shortopt>
  8450.     <doc>Only list the packages that would be downloaded</doc>
  8451.    </pretend>
  8452.   </options>
  8453.   <doc>[channel/]<package> ...
  8454. Installs one or more PEAR packages.  You can specify a package to
  8455. install in four ways:
  8456.  
  8457. "Package-1.0.tgz" : installs from a local file
  8458.  
  8459. "http://example.com/Package-1.0.tgz" : installs from
  8460. anywhere on the net.
  8461.  
  8462. "package.xml" : installs the package described in
  8463. package.xml.  Useful for testing, or for wrapping a PEAR package in
  8464. another package manager such as RPM.
  8465.  
  8466. "Package[-version/state][.tar]" : queries your default channel's server
  8467. ({config master_server}) and downloads the newest package with
  8468. the preferred quality/state ({config preferred_state}).
  8469.  
  8470. To retrieve Package version 1.1, use "Package-1.1," to retrieve
  8471. Package state beta, use "Package-beta."  To retrieve an uncompressed
  8472. file, append .tar (make sure there is no file by the same name first)
  8473.  
  8474. To download a package from another channel, prefix with the channel name like
  8475. "channel/Package"
  8476.  
  8477. More than one package may be specified at once.  It is ok to mix these
  8478. four ways of specifying packages.
  8479. </doc>
  8480.  </install>
  8481.  <upgrade>
  8482.   <summary>Upgrade Package</summary>
  8483.   <function>doInstall</function>
  8484.   <shortcut>up</shortcut>
  8485.   <options>
  8486.    <force>
  8487.     <shortopt>f</shortopt>
  8488.     <doc>overwrite newer installed packages</doc>
  8489.    </force>
  8490.    <loose>
  8491.     <shortopt>l</shortopt>
  8492.     <doc>do not check for recommended dependency version</doc>
  8493.    </loose>
  8494.    <nodeps>
  8495.     <shortopt>n</shortopt>
  8496.     <doc>ignore dependencies, upgrade anyway</doc>
  8497.    </nodeps>
  8498.    <register-only>
  8499.     <shortopt>r</shortopt>
  8500.     <doc>do not install files, only register the package as upgraded</doc>
  8501.    </register-only>
  8502.    <nobuild>
  8503.     <shortopt>B</shortopt>
  8504.     <doc>don't build C extensions</doc>
  8505.    </nobuild>
  8506.    <nocompress>
  8507.     <shortopt>Z</shortopt>
  8508.     <doc>request uncompressed files when downloading</doc>
  8509.    </nocompress>
  8510.    <installroot>
  8511.     <shortopt>R</shortopt>
  8512.     <arg>DIR</arg>
  8513.     <doc>root directory used when installing files (ala PHP's INSTALL_ROOT)</doc>
  8514.    </installroot>
  8515.    <ignore-errors>
  8516.     <doc>force install even if there were errors</doc>
  8517.    </ignore-errors>
  8518.    <alldeps>
  8519.     <shortopt>a</shortopt>
  8520.     <doc>install all required and optional dependencies</doc>
  8521.    </alldeps>
  8522.    <onlyreqdeps>
  8523.     <shortopt>o</shortopt>
  8524.     <doc>install all required dependencies</doc>
  8525.    </onlyreqdeps>
  8526.    <offline>
  8527.     <shortopt>O</shortopt>
  8528.     <doc>do not attempt to download any urls or contact channels</doc>
  8529.    </offline>
  8530.    <pretend>
  8531.     <shortopt>p</shortopt>
  8532.     <doc>Only list the packages that would be downloaded</doc>
  8533.    </pretend>
  8534.   </options>
  8535.   <doc><package> ...
  8536. Upgrades one or more PEAR packages.  See documentation for the
  8537. "install" command for ways to specify a package.
  8538.  
  8539. When upgrading, your package will be updated if the provided new
  8540. package has a higher version number (use the -f option if you need to
  8541. upgrade anyway).
  8542.  
  8543. More than one package may be specified at once.
  8544. </doc>
  8545.  </upgrade>
  8546.  <upgrade-all>
  8547.   <summary>Upgrade All Packages</summary>
  8548.   <function>doInstall</function>
  8549.   <shortcut>ua</shortcut>
  8550.   <options>
  8551.    <nodeps>
  8552.     <shortopt>n</shortopt>
  8553.     <doc>ignore dependencies, upgrade anyway</doc>
  8554.    </nodeps>
  8555.    <register-only>
  8556.     <shortopt>r</shortopt>
  8557.     <doc>do not install files, only register the package as upgraded</doc>
  8558.    </register-only>
  8559.    <nobuild>
  8560.     <shortopt>B</shortopt>
  8561.     <doc>don't build C extensions</doc>
  8562.    </nobuild>
  8563.    <nocompress>
  8564.     <shortopt>Z</shortopt>
  8565.     <doc>request uncompressed files when downloading</doc>
  8566.    </nocompress>
  8567.    <installroot>
  8568.     <shortopt>R</shortopt>
  8569.     <arg>DIR</arg>
  8570.     <doc>root directory used when installing files (ala PHP's INSTALL_ROOT)</doc>
  8571.    </installroot>
  8572.    <ignore-errors>
  8573.     <doc>force install even if there were errors</doc>
  8574.    </ignore-errors>
  8575.    <loose>
  8576.     <doc>do not check for recommended dependency version</doc>
  8577.    </loose>
  8578.   </options>
  8579.   <doc>
  8580. Upgrades all packages that have a newer release available.  Upgrades are
  8581. done only if there is a release available of the state specified in
  8582. "preferred_state" (currently {config preferred_state}), or a state considered
  8583. more stable.
  8584. </doc>
  8585.  </upgrade-all>
  8586.  <uninstall>
  8587.   <summary>Un-install Package</summary>
  8588.   <function>doUninstall</function>
  8589.   <shortcut>un</shortcut>
  8590.   <options>
  8591.    <nodeps>
  8592.     <shortopt>n</shortopt>
  8593.     <doc>ignore dependencies, uninstall anyway</doc>
  8594.    </nodeps>
  8595.    <register-only>
  8596.     <shortopt>r</shortopt>
  8597.     <doc>do not remove files, only register the packages as not installed</doc>
  8598.    </register-only>
  8599.    <installroot>
  8600.     <shortopt>R</shortopt>
  8601.     <arg>DIR</arg>
  8602.     <doc>root directory used when installing files (ala PHP's INSTALL_ROOT)</doc>
  8603.    </installroot>
  8604.    <ignore-errors>
  8605.     <doc>force install even if there were errors</doc>
  8606.    </ignore-errors>
  8607.    <offline>
  8608.     <shortopt>O</shortopt>
  8609.     <doc>do not attempt to uninstall remotely</doc>
  8610.    </offline>
  8611.   </options>
  8612.   <doc>[channel/]<package> ...
  8613. Uninstalls one or more PEAR packages.  More than one package may be
  8614. specified at once.  Prefix with channel name to uninstall from a
  8615. channel not in your default channel ({config default_channel})
  8616. </doc>
  8617.  </uninstall>
  8618.  <bundle>
  8619.   <summary>Unpacks a Pecl Package</summary>
  8620.   <function>doBundle</function>
  8621.   <shortcut>bun</shortcut>
  8622.   <options>
  8623.    <destination>
  8624.     <shortopt>d</shortopt>
  8625.     <arg>DIR</arg>
  8626.     <doc>Optional destination directory for unpacking (defaults to current path or "ext" if exists)</doc>
  8627.    </destination>
  8628.    <force>
  8629.     <shortopt>f</shortopt>
  8630.     <doc>Force the unpacking even if there were errors in the package</doc>
  8631.    </force>
  8632.   </options>
  8633.   <doc><package>
  8634. Unpacks a Pecl Package into the selected location. It will download the
  8635. package if needed.
  8636. </doc>
  8637.  </bundle>
  8638.  <run-scripts>
  8639.   <summary>Run Post-Install Scripts bundled with a package</summary>
  8640.   <function>doRunScripts</function>
  8641.   <shortcut>rs</shortcut>
  8642.   <options />
  8643.   <doc><package>
  8644. Run post-installation scripts in package <package>, if any exist.
  8645. </doc>
  8646.  </run-scripts>
  8647. </commands><?php
  8648. /**
  8649.  * PEAR_Common, the base class for the PEAR Installer
  8650.  *
  8651.  * PHP versions 4 and 5
  8652.  *
  8653.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  8654.  * that is available through the world-wide-web at the following URI:
  8655.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  8656.  * the PHP License and are unable to obtain it through the web, please
  8657.  * send a note to license@php.net so we can mail you a copy immediately.
  8658.  *
  8659.  * @category   pear
  8660.  * @package    PEAR
  8661.  * @author     Stig Bakken <ssb@php.net>
  8662.  * @author     Tomas V. V. Cox <cox@idecnet.com>
  8663.  * @author     Greg Beaver <cellog@php.net>
  8664.  * @copyright  1997-2008 The PHP Group
  8665.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  8666.  * @version    CVS: $Id: Common.php,v 1.160 2008/01/03 20:26:34 cellog Exp $
  8667.  * @link       http://pear.php.net/package/PEAR
  8668.  * @since      File available since Release 0.1.0
  8669.  * @deprecated File deprecated since Release 1.4.0a1
  8670.  */
  8671.  
  8672. /**
  8673.  * Include error handling
  8674.  */
  8675. require_once 'phar://go-pear.phar/' . 'PEAR.php';
  8676.  
  8677. // {{{ constants and globals
  8678.  
  8679. /**
  8680.  * PEAR_Common error when an invalid PHP file is passed to PEAR_Common::analyzeSourceCode()
  8681.  */
  8682. define('PEAR_COMMON_ERROR_INVALIDPHP', 1);
  8683. define('_PEAR_COMMON_PACKAGE_NAME_PREG', '[A-Za-z][a-zA-Z0-9_]+');
  8684. define('PEAR_COMMON_PACKAGE_NAME_PREG', '/^' . _PEAR_COMMON_PACKAGE_NAME_PREG . '\\z/');
  8685.  
  8686. // this should allow: 1, 1.0, 1.0RC1, 1.0dev, 1.0dev123234234234, 1.0a1, 1.0b1, 1.0pl1
  8687. define('_PEAR_COMMON_PACKAGE_VERSION_PREG', '\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?');
  8688. define('PEAR_COMMON_PACKAGE_VERSION_PREG', '/^' . _PEAR_COMMON_PACKAGE_VERSION_PREG . '\\z/i');
  8689.  
  8690. // XXX far from perfect :-)
  8691. define('_PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '(' . _PEAR_COMMON_PACKAGE_NAME_PREG .
  8692.     ')(-([.0-9a-zA-Z]+))?');
  8693. define('PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_PACKAGE_DOWNLOAD_PREG .
  8694.     '\\z/');
  8695.  
  8696. define('_PEAR_CHANNELS_NAME_PREG', '[A-Za-z][a-zA-Z0-9\.]+');
  8697. define('PEAR_CHANNELS_NAME_PREG', '/^' . _PEAR_CHANNELS_NAME_PREG . '\\z/');
  8698.  
  8699. // this should allow any dns or IP address, plus a path - NO UNDERSCORES ALLOWED
  8700. define('_PEAR_CHANNELS_SERVER_PREG', '[a-zA-Z0-9\-]+(?:\.[a-zA-Z0-9\-]+)*(\/[a-zA-Z0-9\-]+)*');
  8701. define('PEAR_CHANNELS_SERVER_PREG', '/^' . _PEAR_CHANNELS_SERVER_PREG . '\\z/i');
  8702.  
  8703. define('_PEAR_CHANNELS_PACKAGE_PREG',  '(' ._PEAR_CHANNELS_SERVER_PREG . ')\/('
  8704.          . _PEAR_COMMON_PACKAGE_NAME_PREG . ')');
  8705. define('PEAR_CHANNELS_PACKAGE_PREG', '/^' . _PEAR_CHANNELS_PACKAGE_PREG . '\\z/i');
  8706.  
  8707. define('_PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '(' . _PEAR_CHANNELS_NAME_PREG . ')::('
  8708.     . _PEAR_COMMON_PACKAGE_NAME_PREG . ')(-([.0-9a-zA-Z]+))?');
  8709. define('PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_CHANNEL_DOWNLOAD_PREG . '\\z/');
  8710.  
  8711. /**
  8712.  * List of temporary files and directories registered by
  8713.  * PEAR_Common::addTempFile().
  8714.  * @var array
  8715.  */
  8716. $GLOBALS['_PEAR_Common_tempfiles'] = array();
  8717.  
  8718. /**
  8719.  * Valid maintainer roles
  8720.  * @var array
  8721.  */
  8722. $GLOBALS['_PEAR_Common_maintainer_roles'] = array('lead','developer','contributor','helper');
  8723.  
  8724. /**
  8725.  * Valid release states
  8726.  * @var array
  8727.  */
  8728. $GLOBALS['_PEAR_Common_release_states'] = array('alpha','beta','stable','snapshot','devel');
  8729.  
  8730. /**
  8731.  * Valid dependency types
  8732.  * @var array
  8733.  */
  8734. $GLOBALS['_PEAR_Common_dependency_types'] = array('pkg','ext','php','prog','ldlib','rtlib','os','websrv','sapi');
  8735.  
  8736. /**
  8737.  * Valid dependency relations
  8738.  * @var array
  8739.  */
  8740. $GLOBALS['_PEAR_Common_dependency_relations'] = array('has','eq','lt','le','gt','ge','not', 'ne');
  8741.  
  8742. /**
  8743.  * Valid file roles
  8744.  * @var array
  8745.  */
  8746. $GLOBALS['_PEAR_Common_file_roles'] = array('php','ext','test','doc','data','src','script');
  8747.  
  8748. /**
  8749.  * Valid replacement types
  8750.  * @var array
  8751.  */
  8752. $GLOBALS['_PEAR_Common_replacement_types'] = array('php-const', 'pear-config', 'package-info');
  8753.  
  8754. /**
  8755.  * Valid "provide" types
  8756.  * @var array
  8757.  */
  8758. $GLOBALS['_PEAR_Common_provide_types'] = array('ext', 'prog', 'class', 'function', 'feature', 'api');
  8759.  
  8760. /**
  8761.  * Valid "provide" types
  8762.  * @var array
  8763.  */
  8764. $GLOBALS['_PEAR_Common_script_phases'] = array('pre-install', 'post-install', 'pre-uninstall', 'post-uninstall', 'pre-build', 'post-build', 'pre-configure', 'post-configure', 'pre-setup', 'post-setup');
  8765.  
  8766. // }}}
  8767.  
  8768. /**
  8769.  * Class providing common functionality for PEAR administration classes.
  8770.  * @category   pear
  8771.  * @package    PEAR
  8772.  * @author     Stig Bakken <ssb@php.net>
  8773.  * @author     Tomas V. V. Cox <cox@idecnet.com>
  8774.  * @author     Greg Beaver <cellog@php.net>
  8775.  * @copyright  1997-2008 The PHP Group
  8776.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  8777.  * @version    Release: 1.7.1
  8778.  * @link       http://pear.php.net/package/PEAR
  8779.  * @since      Class available since Release 1.4.0a1
  8780.  * @deprecated This class will disappear, and its components will be spread
  8781.  *             into smaller classes, like the AT&T breakup, as of Release 1.4.0a1
  8782.  */
  8783. class PEAR_Common extends PEAR
  8784. {
  8785.     // {{{ properties
  8786.  
  8787.     /** stack of elements, gives some sort of XML context */
  8788.     var $element_stack = array();
  8789.  
  8790.     /** name of currently parsed XML element */
  8791.     var $current_element;
  8792.  
  8793.     /** array of attributes of the currently parsed XML element */
  8794.     var $current_attributes = array();
  8795.  
  8796.     /** assoc with information about a package */
  8797.     var $pkginfo = array();
  8798.  
  8799.     /**
  8800.      * User Interface object (PEAR_Frontend_* class).  If null,
  8801.      * the log() method uses print.
  8802.      * @var object
  8803.      */
  8804.     var $ui = null;
  8805.  
  8806.     /**
  8807.      * Configuration object (PEAR_Config).
  8808.      * @var PEAR_Config
  8809.      */
  8810.     var $config = null;
  8811.  
  8812.     var $current_path = null;
  8813.  
  8814.     /**
  8815.      * PEAR_SourceAnalyzer instance
  8816.      * @var object
  8817.      */
  8818.     var $source_analyzer = null;
  8819.     /**
  8820.      * Flag variable used to mark a valid package file
  8821.      * @var boolean
  8822.      * @access private
  8823.      */
  8824.     var $_validPackageFile;
  8825.  
  8826.     // }}}
  8827.  
  8828.     // {{{ constructor
  8829.  
  8830.     /**
  8831.      * PEAR_Common constructor
  8832.      *
  8833.      * @access public
  8834.      */
  8835.     function PEAR_Common()
  8836.     {
  8837.         parent::PEAR();
  8838.         $this->config = &PEAR_Config::singleton();
  8839.         $this->debug = $this->config->get('verbose');
  8840.     }
  8841.  
  8842.     // }}}
  8843.     // {{{ destructor
  8844.  
  8845.     /**
  8846.      * PEAR_Common destructor
  8847.      *
  8848.      * @access private
  8849.      */
  8850.     function _PEAR_Common()
  8851.     {
  8852.         // doesn't work due to bug #14744
  8853.         //$tempfiles = $this->_tempfiles;
  8854.         $tempfiles =& $GLOBALS['_PEAR_Common_tempfiles'];
  8855.         while ($file = array_shift($tempfiles)) {
  8856.             if (@is_dir($file)) {
  8857.                 if (!class_exists('System')) {
  8858.                     require_once 'phar://go-pear.phar/' . 'System.php';
  8859.                 }
  8860.                 System::rm(array('-rf', $file));
  8861.             } elseif (file_exists($file)) {
  8862.                 unlink($file);
  8863.             }
  8864.         }
  8865.     }
  8866.  
  8867.     // }}}
  8868.     // {{{ addTempFile()
  8869.  
  8870.     /**
  8871.      * Register a temporary file or directory.  When the destructor is
  8872.      * executed, all registered temporary files and directories are
  8873.      * removed.
  8874.      *
  8875.      * @param string  $file  name of file or directory
  8876.      *
  8877.      * @return void
  8878.      *
  8879.      * @access public
  8880.      */
  8881.     function addTempFile($file)
  8882.     {
  8883.         if (!class_exists('PEAR_Frontend')) {
  8884.             require_once 'phar://go-pear.phar/' . 'PEAR/Frontend.php';
  8885.         }
  8886.         PEAR_Frontend::addTempFile($file);
  8887.     }
  8888.  
  8889.     // }}}
  8890.     // {{{ mkDirHier()
  8891.  
  8892.     /**
  8893.      * Wrapper to System::mkDir(), creates a directory as well as
  8894.      * any necessary parent directories.
  8895.      *
  8896.      * @param string  $dir  directory name
  8897.      *
  8898.      * @return bool TRUE on success, or a PEAR error
  8899.      *
  8900.      * @access public
  8901.      */
  8902.     function mkDirHier($dir)
  8903.     {
  8904.         $this->log(2, "+ create dir $dir");
  8905.         if (!class_exists('System')) {
  8906.             require_once 'phar://go-pear.phar/' . 'System.php';
  8907.         }
  8908.         return System::mkDir(array('-p', $dir));
  8909.     }
  8910.  
  8911.     // }}}
  8912.     // {{{ log()
  8913.  
  8914.     /**
  8915.      * Logging method.
  8916.      *
  8917.      * @param int    $level  log level (0 is quiet, higher is noisier)
  8918.      * @param string $msg    message to write to the log
  8919.      *
  8920.      * @return void
  8921.      *
  8922.      * @access public
  8923.      * @static
  8924.      */
  8925.     function log($level, $msg, $append_crlf = true)
  8926.     {
  8927.         if ($this->debug >= $level) {
  8928.             if (!class_exists('PEAR_Frontend')) {
  8929.                 require_once 'phar://go-pear.phar/' . 'PEAR/Frontend.php';
  8930.             }
  8931.             $ui = &PEAR_Frontend::singleton();
  8932.             if (is_a($ui, 'PEAR_Frontend')) {
  8933.                 $ui->log($msg, $append_crlf);
  8934.             } else {
  8935.                 print "$msg\n";
  8936.             }
  8937.         }
  8938.     }
  8939.  
  8940.     // }}}
  8941.     // {{{ mkTempDir()
  8942.  
  8943.     /**
  8944.      * Create and register a temporary directory.
  8945.      *
  8946.      * @param string $tmpdir (optional) Directory to use as tmpdir.
  8947.      *                       Will use system defaults (for example
  8948.      *                       /tmp or c:\windows\temp) if not specified
  8949.      *
  8950.      * @return string name of created directory
  8951.      *
  8952.      * @access public
  8953.      */
  8954.     function mkTempDir($tmpdir = '')
  8955.     {
  8956.         if ($tmpdir) {
  8957.             $topt = array('-t', $tmpdir);
  8958.         } else {
  8959.             $topt = array();
  8960.         }
  8961.         $topt = array_merge($topt, array('-d', 'pear'));
  8962.         if (!class_exists('System')) {
  8963.             require_once 'phar://go-pear.phar/' . 'System.php';
  8964.         }
  8965.         if (!$tmpdir = System::mktemp($topt)) {
  8966.             return false;
  8967.         }
  8968.         $this->addTempFile($tmpdir);
  8969.         return $tmpdir;
  8970.     }
  8971.  
  8972.     // }}}
  8973.     // {{{ setFrontendObject()
  8974.  
  8975.     /**
  8976.      * Set object that represents the frontend to be used.
  8977.      *
  8978.      * @param  object Reference of the frontend object
  8979.      * @return void
  8980.      * @access public
  8981.      */
  8982.     function setFrontendObject(&$ui)
  8983.     {
  8984.         $this->ui = &$ui;
  8985.     }
  8986.  
  8987.     // }}}
  8988.  
  8989.     // {{{ infoFromTgzFile()
  8990.  
  8991.     /**
  8992.      * Returns information about a package file.  Expects the name of
  8993.      * a gzipped tar file as input.
  8994.      *
  8995.      * @param string  $file  name of .tgz file
  8996.      *
  8997.      * @return array  array with package information
  8998.      *
  8999.      * @access public
  9000.      * @deprecated use PEAR_PackageFile->fromTgzFile() instead
  9001.      *
  9002.      */
  9003.     function infoFromTgzFile($file)
  9004.     {
  9005.         $packagefile = &new PEAR_PackageFile($this->config);
  9006.         $pf = &$packagefile->fromTgzFile($file, PEAR_VALIDATE_NORMAL);
  9007.         if (PEAR::isError($pf)) {
  9008.             $errs = $pf->getUserinfo();
  9009.             if (is_array($errs)) {
  9010.                 foreach ($errs as $error) {
  9011.                     $e = $this->raiseError($error['message'], $error['code'], null, null, $error);
  9012.                 }
  9013.             }
  9014.             return $pf;
  9015.         }
  9016.         return $this->_postProcessValidPackagexml($pf);
  9017.     }
  9018.  
  9019.     // }}}
  9020.     // {{{ infoFromDescriptionFile()
  9021.  
  9022.     /**
  9023.      * Returns information about a package file.  Expects the name of
  9024.      * a package xml file as input.
  9025.      *
  9026.      * @param string  $descfile  name of package xml file
  9027.      *
  9028.      * @return array  array with package information
  9029.      *
  9030.      * @access public
  9031.      * @deprecated use PEAR_PackageFile->fromPackageFile() instead
  9032.      *
  9033.      */
  9034.     function infoFromDescriptionFile($descfile)
  9035.     {
  9036.         $packagefile = &new PEAR_PackageFile($this->config);
  9037.         $pf = &$packagefile->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL);
  9038.         if (PEAR::isError($pf)) {
  9039.             $errs = $pf->getUserinfo();
  9040.             if (is_array($errs)) {
  9041.                 foreach ($errs as $error) {
  9042.                     $e = $this->raiseError($error['message'], $error['code'], null, null, $error);
  9043.                 }
  9044.             }
  9045.             return $pf;
  9046.         }
  9047.         return $this->_postProcessValidPackagexml($pf);
  9048.     }
  9049.  
  9050.     // }}}
  9051.     // {{{ infoFromString()
  9052.  
  9053.     /**
  9054.      * Returns information about a package file.  Expects the contents
  9055.      * of a package xml file as input.
  9056.      *
  9057.      * @param string  $data  contents of package.xml file
  9058.      *
  9059.      * @return array   array with package information
  9060.      *
  9061.      * @access public
  9062.      * @deprecated use PEAR_PackageFile->fromXmlstring() instead
  9063.      *
  9064.      */
  9065.     function infoFromString($data)
  9066.     {
  9067.         $packagefile = &new PEAR_PackageFile($this->config);
  9068.         $pf = &$packagefile->fromXmlString($data, PEAR_VALIDATE_NORMAL, false);
  9069.         if (PEAR::isError($pf)) {
  9070.             $errs = $pf->getUserinfo();
  9071.             if (is_array($errs)) {
  9072.                 foreach ($errs as $error) {
  9073.                     $e = $this->raiseError($error['message'], $error['code'], null, null, $error);
  9074.                 }
  9075.             }
  9076.             return $pf;
  9077.         }
  9078.         return $this->_postProcessValidPackagexml($pf);
  9079.     }
  9080.     // }}}
  9081.  
  9082.     /**
  9083.      * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  9084.      * @return array
  9085.      */
  9086.     function _postProcessValidPackagexml(&$pf)
  9087.     {
  9088.         if (is_a($pf, 'PEAR_PackageFile_v2')) {
  9089.             // sort of make this into a package.xml 1.0-style array
  9090.             // changelog is not converted to old format.
  9091.             $arr = $pf->toArray(true);
  9092.             $arr = array_merge($arr, $arr['old']);
  9093.             unset($arr['old']);
  9094.             unset($arr['xsdversion']);
  9095.             unset($arr['contents']);
  9096.             unset($arr['compatible']);
  9097.             unset($arr['channel']);
  9098.             unset($arr['uri']);
  9099.             unset($arr['dependencies']);
  9100.             unset($arr['phprelease']);
  9101.             unset($arr['extsrcrelease']);
  9102.             unset($arr['zendextsrcrelease']);
  9103.             unset($arr['extbinrelease']);
  9104.             unset($arr['zendextbinrelease']);
  9105.             unset($arr['bundle']);
  9106.             unset($arr['lead']);
  9107.             unset($arr['developer']);
  9108.             unset($arr['helper']);
  9109.             unset($arr['contributor']);
  9110.             $arr['filelist'] = $pf->getFilelist();
  9111.             $this->pkginfo = $arr;
  9112.             return $arr;
  9113.         } else {
  9114.             $this->pkginfo = $pf->toArray();
  9115.             return $this->pkginfo;
  9116.         }
  9117.     }
  9118.     // {{{ infoFromAny()
  9119.  
  9120.     /**
  9121.      * Returns package information from different sources
  9122.      *
  9123.      * This method is able to extract information about a package
  9124.      * from a .tgz archive or from a XML package definition file.
  9125.      *
  9126.      * @access public
  9127.      * @param  string Filename of the source ('package.xml', '<package>.tgz')
  9128.      * @return string
  9129.      * @deprecated use PEAR_PackageFile->fromAnyFile() instead
  9130.      */
  9131.     function infoFromAny($info)
  9132.     {
  9133.         if (is_string($info) && file_exists($info)) {
  9134.             $packagefile = &new PEAR_PackageFile($this->config);
  9135.             $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL);
  9136.             if (PEAR::isError($pf)) {
  9137.                 $errs = $pf->getUserinfo();
  9138.                 if (is_array($errs)) {
  9139.                     foreach ($errs as $error) {
  9140.                         $e = $this->raiseError($error['message'], $error['code'], null, null, $error);
  9141.                     }
  9142.                 }
  9143.                 return $pf;
  9144.             }
  9145.             return $this->_postProcessValidPackagexml($pf);
  9146.         }
  9147.         return $info;
  9148.     }
  9149.  
  9150.     // }}}
  9151.     // {{{ xmlFromInfo()
  9152.  
  9153.     /**
  9154.      * Return an XML document based on the package info (as returned
  9155.      * by the PEAR_Common::infoFrom* methods).
  9156.      *
  9157.      * @param array  $pkginfo  package info
  9158.      *
  9159.      * @return string XML data
  9160.      *
  9161.      * @access public
  9162.      * @deprecated use a PEAR_PackageFile_v* object's generator instead
  9163.      */
  9164.     function xmlFromInfo($pkginfo)
  9165.     {
  9166.         $config = &PEAR_Config::singleton();
  9167.         $packagefile = &new PEAR_PackageFile($config);
  9168.         $pf = &$packagefile->fromArray($pkginfo);
  9169.         $gen = &$pf->getDefaultGenerator();
  9170.         return $gen->toXml(PEAR_VALIDATE_PACKAGING);
  9171.     }
  9172.  
  9173.     // }}}
  9174.     // {{{ validatePackageInfo()
  9175.  
  9176.     /**
  9177.      * Validate XML package definition file.
  9178.      *
  9179.      * @param  string $info Filename of the package archive or of the
  9180.      *                package definition file
  9181.      * @param  array $errors Array that will contain the errors
  9182.      * @param  array $warnings Array that will contain the warnings
  9183.      * @param  string $dir_prefix (optional) directory where source files
  9184.      *                may be found, or empty if they are not available
  9185.      * @access public
  9186.      * @return boolean
  9187.      * @deprecated use the validation of PEAR_PackageFile objects
  9188.      */
  9189.     function validatePackageInfo($info, &$errors, &$warnings, $dir_prefix = '')
  9190.     {
  9191.         $config = &PEAR_Config::singleton();
  9192.         $packagefile = &new PEAR_PackageFile($config);
  9193.         PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  9194.         if (strpos($info, '<?xml') !== false) {
  9195.             $pf = &$packagefile->fromXmlString($info, PEAR_VALIDATE_NORMAL, '');
  9196.         } else {
  9197.             $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL);
  9198.         }
  9199.         PEAR::staticPopErrorHandling();
  9200.         if (PEAR::isError($pf)) {
  9201.             $errs = $pf->getUserinfo();
  9202.             if (is_array($errs)) {
  9203.                 foreach ($errs as $error) {
  9204.                     if ($error['level'] == 'error') {
  9205.                         $errors[] = $error['message'];
  9206.                     } else {
  9207.                         $warnings[] = $error['message'];
  9208.                     }
  9209.                 }
  9210.             }
  9211.             return false;
  9212.         }
  9213.         return true;
  9214.     }
  9215.  
  9216.     // }}}
  9217.     // {{{ buildProvidesArray()
  9218.  
  9219.     /**
  9220.      * Build a "provides" array from data returned by
  9221.      * analyzeSourceCode().  The format of the built array is like
  9222.      * this:
  9223.      *
  9224.      *  array(
  9225.      *    'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'),
  9226.      *    ...
  9227.      *  )
  9228.      *
  9229.      *
  9230.      * @param array $srcinfo array with information about a source file
  9231.      * as returned by the analyzeSourceCode() method.
  9232.      *
  9233.      * @return void
  9234.      *
  9235.      * @access public
  9236.      *
  9237.      */
  9238.     function buildProvidesArray($srcinfo)
  9239.     {
  9240.         $file = basename($srcinfo['source_file']);
  9241.         $pn = '';
  9242.         if (isset($this->_packageName)) {
  9243.             $pn = $this->_packageName;
  9244.         }
  9245.         $pnl = strlen($pn);
  9246.         foreach ($srcinfo['declared_classes'] as $class) {
  9247.             $key = "class;$class";
  9248.             if (isset($this->pkginfo['provides'][$key])) {
  9249.                 continue;
  9250.             }
  9251.             $this->pkginfo['provides'][$key] =
  9252.                 array('file'=> $file, 'type' => 'class', 'name' => $class);
  9253.             if (isset($srcinfo['inheritance'][$class])) {
  9254.                 $this->pkginfo['provides'][$key]['extends'] =
  9255.                     $srcinfo['inheritance'][$class];
  9256.             }
  9257.         }
  9258.         foreach ($srcinfo['declared_methods'] as $class => $methods) {
  9259.             foreach ($methods as $method) {
  9260.                 $function = "$class::$method";
  9261.                 $key = "function;$function";
  9262.                 if ($method{0} == '_' || !strcasecmp($method, $class) ||
  9263.                     isset($this->pkginfo['provides'][$key])) {
  9264.                     continue;
  9265.                 }
  9266.                 $this->pkginfo['provides'][$key] =
  9267.                     array('file'=> $file, 'type' => 'function', 'name' => $function);
  9268.             }
  9269.         }
  9270.  
  9271.         foreach ($srcinfo['declared_functions'] as $function) {
  9272.             $key = "function;$function";
  9273.             if ($function{0} == '_' || isset($this->pkginfo['provides'][$key])) {
  9274.                 continue;
  9275.             }
  9276.             if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) {
  9277.                 $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\"";
  9278.             }
  9279.             $this->pkginfo['provides'][$key] =
  9280.                 array('file'=> $file, 'type' => 'function', 'name' => $function);
  9281.         }
  9282.     }
  9283.  
  9284.     // }}}
  9285.     // {{{ analyzeSourceCode()
  9286.  
  9287.     /**
  9288.      * Analyze the source code of the given PHP file
  9289.      *
  9290.      * @param  string Filename of the PHP file
  9291.      * @return mixed
  9292.      * @access public
  9293.      */
  9294.     function analyzeSourceCode($file)
  9295.     {
  9296.         if (!function_exists("token_get_all")) {
  9297.             return false;
  9298.         }
  9299.         if (!defined('T_DOC_COMMENT')) {
  9300.             define('T_DOC_COMMENT', T_COMMENT);
  9301.         }
  9302.         if (!defined('T_INTERFACE')) {
  9303.             define('T_INTERFACE', -1);
  9304.         }
  9305.         if (!defined('T_IMPLEMENTS')) {
  9306.             define('T_IMPLEMENTS', -1);
  9307.         }
  9308.         if (!$fp = @fopen($file, "r")) {
  9309.             return false;
  9310.         }
  9311.         fclose($fp);
  9312.         $contents = file_get_contents($file);
  9313.         $tokens = token_get_all($contents);
  9314. /*
  9315.         for ($i = 0; $i < sizeof($tokens); $i++) {
  9316.             @list($token, $data) = $tokens[$i];
  9317.             if (is_string($token)) {
  9318.                 var_dump($token);
  9319.             } else {
  9320.                 print token_name($token) . ' ';
  9321.                 var_dump(rtrim($data));
  9322.             }
  9323.         }
  9324. */
  9325.         $look_for = 0;
  9326.         $paren_level = 0;
  9327.         $bracket_level = 0;
  9328.         $brace_level = 0;
  9329.         $lastphpdoc = '';
  9330.         $current_class = '';
  9331.         $current_interface = '';
  9332.         $current_class_level = -1;
  9333.         $current_function = '';
  9334.         $current_function_level = -1;
  9335.         $declared_classes = array();
  9336.         $declared_interfaces = array();
  9337.         $declared_functions = array();
  9338.         $declared_methods = array();
  9339.         $used_classes = array();
  9340.         $used_functions = array();
  9341.         $extends = array();
  9342.         $implements = array();
  9343.         $nodeps = array();
  9344.         $inquote = false;
  9345.         $interface = false;
  9346.         for ($i = 0; $i < sizeof($tokens); $i++) {
  9347.             if (is_array($tokens[$i])) {
  9348.                 list($token, $data) = $tokens[$i];
  9349.             } else {
  9350.                 $token = $tokens[$i];
  9351.                 $data = '';
  9352.             }
  9353.             if ($inquote) {
  9354.                 if ($token != '"') {
  9355.                     continue;
  9356.                 } else {
  9357.                     $inquote = false;
  9358.                     continue;
  9359.                 }
  9360.             }
  9361.             switch ($token) {
  9362.                 case T_WHITESPACE:
  9363.                     continue;
  9364.                 case ';':
  9365.                     if ($interface) {
  9366.                         $current_function = '';
  9367.                         $current_function_level = -1;
  9368.                     }
  9369.                     break;
  9370.                 case '"':
  9371.                     $inquote = true;
  9372.                     break;
  9373.                 case T_CURLY_OPEN:
  9374.                 case T_DOLLAR_OPEN_CURLY_BRACES:
  9375.                 case '{': $brace_level++; continue 2;
  9376.                 case '}':
  9377.                     $brace_level--;
  9378.                     if ($current_class_level == $brace_level) {
  9379.                         $current_class = '';
  9380.                         $current_class_level = -1;
  9381.                     }
  9382.                     if ($current_function_level == $brace_level) {
  9383.                         $current_function = '';
  9384.                         $current_function_level = -1;
  9385.                     }
  9386.                     continue 2;
  9387.                 case '[': $bracket_level++; continue 2;
  9388.                 case ']': $bracket_level--; continue 2;
  9389.                 case '(': $paren_level++;   continue 2;
  9390.                 case ')': $paren_level--;   continue 2;
  9391.                 case T_INTERFACE:
  9392.                     $interface = true;
  9393.                 case T_CLASS:
  9394.                     if (($current_class_level != -1) || ($current_function_level != -1)) {
  9395.                         PEAR::raiseError("Parser error: invalid PHP found in file \"$file\"",
  9396.                             PEAR_COMMON_ERROR_INVALIDPHP);
  9397.                         return false;
  9398.                     }
  9399.                 case T_FUNCTION:
  9400.                 case T_NEW:
  9401.                 case T_EXTENDS:
  9402.                 case T_IMPLEMENTS:
  9403.                     $look_for = $token;
  9404.                     continue 2;
  9405.                 case T_STRING:
  9406.                     if (version_compare(zend_version(), '2.0', '<')) {
  9407.                         if (in_array(strtolower($data),
  9408.                             array('public', 'private', 'protected', 'abstract',
  9409.                                   'interface', 'implements', 'throw') 
  9410.                                  )) {
  9411.                             PEAR::raiseError('Error: PHP5 token encountered in ' . $file . 
  9412.                             'packaging should be done in PHP 5');
  9413.                             return false;
  9414.                         }
  9415.                     }
  9416.                     if ($look_for == T_CLASS) {
  9417.                         $current_class = $data;
  9418.                         $current_class_level = $brace_level;
  9419.                         $declared_classes[] = $current_class;
  9420.                     } elseif ($look_for == T_INTERFACE) {
  9421.                         $current_interface = $data;
  9422.                         $current_class_level = $brace_level;
  9423.                         $declared_interfaces[] = $current_interface;
  9424.                     } elseif ($look_for == T_IMPLEMENTS) {
  9425.                         $implements[$current_class] = $data;
  9426.                     } elseif ($look_for == T_EXTENDS) {
  9427.                         $extends[$current_class] = $data;
  9428.                     } elseif ($look_for == T_FUNCTION) {
  9429.                         if ($current_class) {
  9430.                             $current_function = "$current_class::$data";
  9431.                             $declared_methods[$current_class][] = $data;
  9432.                         } elseif ($current_interface) {
  9433.                             $current_function = "$current_interface::$data";
  9434.                             $declared_methods[$current_interface][] = $data;
  9435.                         } else {
  9436.                             $current_function = $data;
  9437.                             $declared_functions[] = $current_function;
  9438.                         }
  9439.                         $current_function_level = $brace_level;
  9440.                         $m = array();
  9441.                     } elseif ($look_for == T_NEW) {
  9442.                         $used_classes[$data] = true;
  9443.                     }
  9444.                     $look_for = 0;
  9445.                     continue 2;
  9446.                 case T_VARIABLE:
  9447.                     $look_for = 0;
  9448.                     continue 2;
  9449.                 case T_DOC_COMMENT:
  9450.                 case T_COMMENT:
  9451.                     if (preg_match('!^/\*\*\s!', $data)) {
  9452.                         $lastphpdoc = $data;
  9453.                         if (preg_match_all('/@nodep\s+(\S+)/', $lastphpdoc, $m)) {
  9454.                             $nodeps = array_merge($nodeps, $m[1]);
  9455.                         }
  9456.                     }
  9457.                     continue 2;
  9458.                 case T_DOUBLE_COLON:
  9459.                     if (!($tokens[$i - 1][0] == T_WHITESPACE || $tokens[$i - 1][0] == T_STRING)) {
  9460.                         PEAR::raiseError("Parser error: invalid PHP found in file \"$file\"",
  9461.                             PEAR_COMMON_ERROR_INVALIDPHP);
  9462.                         return false;
  9463.                     }
  9464.                     $class = $tokens[$i - 1][1];
  9465.                     if (strtolower($class) != 'parent') {
  9466.                         $used_classes[$class] = true;
  9467.                     }
  9468.                     continue 2;
  9469.             }
  9470.         }
  9471.         return array(
  9472.             "source_file" => $file,
  9473.             "declared_classes" => $declared_classes,
  9474.             "declared_interfaces" => $declared_interfaces,
  9475.             "declared_methods" => $declared_methods,
  9476.             "declared_functions" => $declared_functions,
  9477.             "used_classes" => array_diff(array_keys($used_classes), $nodeps),
  9478.             "inheritance" => $extends,
  9479.             "implements" => $implements,
  9480.             );
  9481.     }
  9482.  
  9483.     // }}}
  9484.     // {{{  betterStates()
  9485.  
  9486.     /**
  9487.      * Return an array containing all of the states that are more stable than
  9488.      * or equal to the passed in state
  9489.      *
  9490.      * @param string Release state
  9491.      * @param boolean Determines whether to include $state in the list
  9492.      * @return false|array False if $state is not a valid release state
  9493.      */
  9494.     function betterStates($state, $include = false)
  9495.     {
  9496.         static $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable');
  9497.         $i = array_search($state, $states);
  9498.         if ($i === false) {
  9499.             return false;
  9500.         }
  9501.         if ($include) {
  9502.             $i--;
  9503.         }
  9504.         return array_slice($states, $i + 1);
  9505.     }
  9506.  
  9507.     // }}}
  9508.     // {{{ detectDependencies()
  9509.  
  9510.     function detectDependencies($any, $status_callback = null)
  9511.     {
  9512.         if (!function_exists("token_get_all")) {
  9513.             return false;
  9514.         }
  9515.         if (PEAR::isError($info = $this->infoFromAny($any))) {
  9516.             return $this->raiseError($info);
  9517.         }
  9518.         if (!is_array($info)) {
  9519.             return false;
  9520.         }
  9521.         $deps = array();
  9522.         $used_c = $decl_c = $decl_f = $decl_m = array();
  9523.         foreach ($info['filelist'] as $file => $fa) {
  9524.             $tmp = $this->analyzeSourceCode($file);
  9525.             $used_c = @array_merge($used_c, $tmp['used_classes']);
  9526.             $decl_c = @array_merge($decl_c, $tmp['declared_classes']);
  9527.             $decl_f = @array_merge($decl_f, $tmp['declared_functions']);
  9528.             $decl_m = @array_merge($decl_m, $tmp['declared_methods']);
  9529.             $inheri = @array_merge($inheri, $tmp['inheritance']);
  9530.         }
  9531.         $used_c = array_unique($used_c);
  9532.         $decl_c = array_unique($decl_c);
  9533.         $undecl_c = array_diff($used_c, $decl_c);
  9534.         return array('used_classes' => $used_c,
  9535.                      'declared_classes' => $decl_c,
  9536.                      'declared_methods' => $decl_m,
  9537.                      'declared_functions' => $decl_f,
  9538.                      'undeclared_classes' => $undecl_c,
  9539.                      'inheritance' => $inheri,
  9540.                      );
  9541.     }
  9542.  
  9543.     // }}}
  9544.     // {{{ getUserRoles()
  9545.  
  9546.     /**
  9547.      * Get the valid roles for a PEAR package maintainer
  9548.      *
  9549.      * @return array
  9550.      * @static
  9551.      */
  9552.     function getUserRoles()
  9553.     {
  9554.         return $GLOBALS['_PEAR_Common_maintainer_roles'];
  9555.     }
  9556.  
  9557.     // }}}
  9558.     // {{{ getReleaseStates()
  9559.  
  9560.     /**
  9561.      * Get the valid package release states of packages
  9562.      *
  9563.      * @return array
  9564.      * @static
  9565.      */
  9566.     function getReleaseStates()
  9567.     {
  9568.         return $GLOBALS['_PEAR_Common_release_states'];
  9569.     }
  9570.  
  9571.     // }}}
  9572.     // {{{ getDependencyTypes()
  9573.  
  9574.     /**
  9575.      * Get the implemented dependency types (php, ext, pkg etc.)
  9576.      *
  9577.      * @return array
  9578.      * @static
  9579.      */
  9580.     function getDependencyTypes()
  9581.     {
  9582.         return $GLOBALS['_PEAR_Common_dependency_types'];
  9583.     }
  9584.  
  9585.     // }}}
  9586.     // {{{ getDependencyRelations()
  9587.  
  9588.     /**
  9589.      * Get the implemented dependency relations (has, lt, ge etc.)
  9590.      *
  9591.      * @return array
  9592.      * @static
  9593.      */
  9594.     function getDependencyRelations()
  9595.     {
  9596.         return $GLOBALS['_PEAR_Common_dependency_relations'];
  9597.     }
  9598.  
  9599.     // }}}
  9600.     // {{{ getFileRoles()
  9601.  
  9602.     /**
  9603.      * Get the implemented file roles
  9604.      *
  9605.      * @return array
  9606.      * @static
  9607.      */
  9608.     function getFileRoles()
  9609.     {
  9610.         return $GLOBALS['_PEAR_Common_file_roles'];
  9611.     }
  9612.  
  9613.     // }}}
  9614.     // {{{ getReplacementTypes()
  9615.  
  9616.     /**
  9617.      * Get the implemented file replacement types in
  9618.      *
  9619.      * @return array
  9620.      * @static
  9621.      */
  9622.     function getReplacementTypes()
  9623.     {
  9624.         return $GLOBALS['_PEAR_Common_replacement_types'];
  9625.     }
  9626.  
  9627.     // }}}
  9628.     // {{{ getProvideTypes()
  9629.  
  9630.     /**
  9631.      * Get the implemented file replacement types in
  9632.      *
  9633.      * @return array
  9634.      * @static
  9635.      */
  9636.     function getProvideTypes()
  9637.     {
  9638.         return $GLOBALS['_PEAR_Common_provide_types'];
  9639.     }
  9640.  
  9641.     // }}}
  9642.     // {{{ getScriptPhases()
  9643.  
  9644.     /**
  9645.      * Get the implemented file replacement types in
  9646.      *
  9647.      * @return array
  9648.      * @static
  9649.      */
  9650.     function getScriptPhases()
  9651.     {
  9652.         return $GLOBALS['_PEAR_Common_script_phases'];
  9653.     }
  9654.  
  9655.     // }}}
  9656.     // {{{ validPackageName()
  9657.  
  9658.     /**
  9659.      * Test whether a string contains a valid package name.
  9660.      *
  9661.      * @param string $name the package name to test
  9662.      *
  9663.      * @return bool
  9664.      *
  9665.      * @access public
  9666.      */
  9667.     function validPackageName($name)
  9668.     {
  9669.         return (bool)preg_match(PEAR_COMMON_PACKAGE_NAME_PREG, $name);
  9670.     }
  9671.  
  9672.  
  9673.     // }}}
  9674.     // {{{ validPackageVersion()
  9675.  
  9676.     /**
  9677.      * Test whether a string contains a valid package version.
  9678.      *
  9679.      * @param string $ver the package version to test
  9680.      *
  9681.      * @return bool
  9682.      *
  9683.      * @access public
  9684.      */
  9685.     function validPackageVersion($ver)
  9686.     {
  9687.         return (bool)preg_match(PEAR_COMMON_PACKAGE_VERSION_PREG, $ver);
  9688.     }
  9689.  
  9690.  
  9691.     // }}}
  9692.  
  9693.     // {{{ downloadHttp()
  9694.  
  9695.     /**
  9696.      * Download a file through HTTP.  Considers suggested file name in
  9697.      * Content-disposition: header and can run a callback function for
  9698.      * different events.  The callback will be called with two
  9699.      * parameters: the callback type, and parameters.  The implemented
  9700.      * callback types are:
  9701.      *
  9702.      *  'setup'       called at the very beginning, parameter is a UI object
  9703.      *                that should be used for all output
  9704.      *  'message'     the parameter is a string with an informational message
  9705.      *  'saveas'      may be used to save with a different file name, the
  9706.      *                parameter is the filename that is about to be used.
  9707.      *                If a 'saveas' callback returns a non-empty string,
  9708.      *                that file name will be used as the filename instead.
  9709.      *                Note that $save_dir will not be affected by this, only
  9710.      *                the basename of the file.
  9711.      *  'start'       download is starting, parameter is number of bytes
  9712.      *                that are expected, or -1 if unknown
  9713.      *  'bytesread'   parameter is the number of bytes read so far
  9714.      *  'done'        download is complete, parameter is the total number
  9715.      *                of bytes read
  9716.      *  'connfailed'  if the TCP connection fails, this callback is called
  9717.      *                with array(host,port,errno,errmsg)
  9718.      *  'writefailed' if writing to disk fails, this callback is called
  9719.      *                with array(destfile,errmsg)
  9720.      *
  9721.      * If an HTTP proxy has been configured (http_proxy PEAR_Config
  9722.      * setting), the proxy will be used.
  9723.      *
  9724.      * @param string  $url       the URL to download
  9725.      * @param object  $ui        PEAR_Frontend_* instance
  9726.      * @param object  $config    PEAR_Config instance
  9727.      * @param string  $save_dir  (optional) directory to save file in
  9728.      * @param mixed   $callback  (optional) function/method to call for status
  9729.      *                           updates
  9730.      *
  9731.      * @return string  Returns the full path of the downloaded file or a PEAR
  9732.      *                 error on failure.  If the error is caused by
  9733.      *                 socket-related errors, the error object will
  9734.      *                 have the fsockopen error code available through
  9735.      *                 getCode().
  9736.      *
  9737.      * @access public
  9738.      * @deprecated in favor of PEAR_Downloader::downloadHttp()
  9739.      */
  9740.     function downloadHttp($url, &$ui, $save_dir = '.', $callback = null)
  9741.     {
  9742.         if (!class_exists('PEAR_Downloader')) {
  9743.             require_once 'phar://go-pear.phar/' . 'PEAR/Downloader.php';
  9744.         }
  9745.         return PEAR_Downloader::downloadHttp($url, $ui, $save_dir, $callback);
  9746.     }
  9747.  
  9748.     // }}}
  9749.  
  9750.     /**
  9751.      * @param string $path relative or absolute include path
  9752.      * @return boolean
  9753.      * @static
  9754.      */
  9755.     function isIncludeable($path)
  9756.     {
  9757.         if (file_exists($path) && is_readable($path)) {
  9758.             return true;
  9759.         }
  9760.         $ipath = explode(PATH_SEPARATOR, ini_get('include_path'));
  9761.         foreach ($ipath as $include) {
  9762.             $test = realpath($include . DIRECTORY_SEPARATOR . $path);
  9763.             if (file_exists($test) && is_readable($test)) {
  9764.                 return true;
  9765.             }
  9766.         }
  9767.         return false;
  9768.     }
  9769. }
  9770. require_once 'phar://go-pear.phar/' . 'PEAR/Config.php';
  9771. require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile.php';
  9772. ?><?php
  9773. /**
  9774.  * PEAR_Config, customized configuration handling for the PEAR Installer
  9775.  *
  9776.  * PHP versions 4 and 5
  9777.  *
  9778.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  9779.  * that is available through the world-wide-web at the following URI:
  9780.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  9781.  * the PHP License and are unable to obtain it through the web, please
  9782.  * send a note to license@php.net so we can mail you a copy immediately.
  9783.  *
  9784.  * @category   pear
  9785.  * @package    PEAR
  9786.  * @author     Stig Bakken <ssb@php.net>
  9787.  * @author     Greg Beaver <cellog@php.net>
  9788.  * @copyright  1997-2008 The PHP Group
  9789.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  9790.  * @version    CVS: $Id: Config.php,v 1.144 2008/01/03 20:26:34 cellog Exp $
  9791.  * @link       http://pear.php.net/package/PEAR
  9792.  * @since      File available since Release 0.1
  9793.  */
  9794.  
  9795. /**
  9796.  * Required for error handling
  9797.  */
  9798. require_once 'phar://go-pear.phar/' . 'PEAR.php';
  9799. require_once 'phar://go-pear.phar/' . 'PEAR/Registry.php';
  9800. require_once 'phar://go-pear.phar/' . 'PEAR/Installer/Role.php';
  9801. require_once 'phar://go-pear.phar/' . 'System.php';
  9802. require_once 'phar://go-pear.phar/' . 'PEAR/Remote.php';
  9803.  
  9804. /**
  9805.  * Last created PEAR_Config instance.
  9806.  * @var object
  9807.  */
  9808. $GLOBALS['_PEAR_Config_instance'] = null;
  9809. if (!defined('PEAR_INSTALL_DIR') || !PEAR_INSTALL_DIR) {
  9810.     $PEAR_INSTALL_DIR = PHP_LIBDIR . DIRECTORY_SEPARATOR . 'pear';
  9811. } else {
  9812.     $PEAR_INSTALL_DIR = PEAR_INSTALL_DIR;
  9813. }
  9814.  
  9815. // Below we define constants with default values for all configuration
  9816. // parameters except username/password.  All of them can have their
  9817. // defaults set through environment variables.  The reason we use the
  9818. // PHP_ prefix is for some security, PHP protects environment
  9819. // variables starting with PHP_*.
  9820.  
  9821. // default channel and preferred mirror is based on whether we are invoked through
  9822. // the "pear" or the "pecl" command
  9823.  
  9824. if (!defined('PEAR_RUNTYPE') || PEAR_RUNTYPE == 'pear') {
  9825.     define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pear.php.net');
  9826. } else {
  9827.     define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pecl.php.net');
  9828. }
  9829.  
  9830. if (getenv('PHP_PEAR_SYSCONF_DIR')) {
  9831.     define('PEAR_CONFIG_SYSCONFDIR', getenv('PHP_PEAR_SYSCONF_DIR'));
  9832. } elseif (getenv('SystemRoot')) {
  9833.     define('PEAR_CONFIG_SYSCONFDIR', getenv('SystemRoot'));
  9834. } else {
  9835.     define('PEAR_CONFIG_SYSCONFDIR', PHP_SYSCONFDIR);
  9836. }
  9837.  
  9838. // Default for master_server
  9839. if (getenv('PHP_PEAR_MASTER_SERVER')) {
  9840.     define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', getenv('PHP_PEAR_MASTER_SERVER'));
  9841. } else {
  9842.     define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', 'pear.php.net');
  9843. }
  9844.  
  9845. // Default for http_proxy
  9846. if (getenv('PHP_PEAR_HTTP_PROXY')) {
  9847.     define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', getenv('PHP_PEAR_HTTP_PROXY'));
  9848. } elseif (getenv('http_proxy')) {
  9849.     define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', getenv('http_proxy'));
  9850. } else {
  9851.     define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', '');
  9852. }
  9853.  
  9854. // Default for php_dir
  9855. if (getenv('PHP_PEAR_INSTALL_DIR')) {
  9856.     define('PEAR_CONFIG_DEFAULT_PHP_DIR', getenv('PHP_PEAR_INSTALL_DIR'));
  9857. } else {
  9858.     if (file_exists($PEAR_INSTALL_DIR) && is_dir($PEAR_INSTALL_DIR)) {
  9859.         define('PEAR_CONFIG_DEFAULT_PHP_DIR',
  9860.                $PEAR_INSTALL_DIR);
  9861.     } else {
  9862.         define('PEAR_CONFIG_DEFAULT_PHP_DIR', $PEAR_INSTALL_DIR);
  9863.     }
  9864. }
  9865.  
  9866. // Default for ext_dir
  9867. if (getenv('PHP_PEAR_EXTENSION_DIR')) {
  9868.     define('PEAR_CONFIG_DEFAULT_EXT_DIR', getenv('PHP_PEAR_EXTENSION_DIR'));
  9869. } else {
  9870.     if (ini_get('extension_dir')) {
  9871.         define('PEAR_CONFIG_DEFAULT_EXT_DIR', ini_get('extension_dir'));
  9872.     } elseif (defined('PEAR_EXTENSION_DIR') &&
  9873.               file_exists(PEAR_EXTENSION_DIR) && is_dir(PEAR_EXTENSION_DIR)) {
  9874.         define('PEAR_CONFIG_DEFAULT_EXT_DIR', PEAR_EXTENSION_DIR);
  9875.     } elseif (defined('PHP_EXTENSION_DIR')) {
  9876.         define('PEAR_CONFIG_DEFAULT_EXT_DIR', PHP_EXTENSION_DIR);
  9877.     } else {
  9878.         define('PEAR_CONFIG_DEFAULT_EXT_DIR', '.');
  9879.     }
  9880. }
  9881.  
  9882. // Default for doc_dir
  9883. if (getenv('PHP_PEAR_DOC_DIR')) {
  9884.     define('PEAR_CONFIG_DEFAULT_DOC_DIR', getenv('PHP_PEAR_DOC_DIR'));
  9885. } else {
  9886.     define('PEAR_CONFIG_DEFAULT_DOC_DIR',
  9887.            $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'docs');
  9888. }
  9889.  
  9890. // Default for bin_dir
  9891. if (getenv('PHP_PEAR_BIN_DIR')) {
  9892.     define('PEAR_CONFIG_DEFAULT_BIN_DIR', getenv('PHP_PEAR_BIN_DIR'));
  9893. } else {
  9894.     define('PEAR_CONFIG_DEFAULT_BIN_DIR', PHP_BINDIR);
  9895. }
  9896.  
  9897. // Default for data_dir
  9898. if (getenv('PHP_PEAR_DATA_DIR')) {
  9899.     define('PEAR_CONFIG_DEFAULT_DATA_DIR', getenv('PHP_PEAR_DATA_DIR'));
  9900. } else {
  9901.     define('PEAR_CONFIG_DEFAULT_DATA_DIR',
  9902.            $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'data');
  9903. }
  9904.  
  9905. // Default for cfg_dir
  9906. if (getenv('PHP_PEAR_CFG_DIR')) {
  9907.     define('PEAR_CONFIG_DEFAULT_CFG_DIR', getenv('PHP_PEAR_CFG_DIR'));
  9908. } else {
  9909.     define('PEAR_CONFIG_DEFAULT_CFG_DIR',
  9910.            $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'cfg');
  9911. }
  9912.  
  9913. // Default for www_dir
  9914. if (getenv('PHP_PEAR_WWW_DIR')) {
  9915.     define('PEAR_CONFIG_DEFAULT_WWW_DIR', getenv('PHP_PEAR_WWW_DIR'));
  9916. } else {
  9917.     define('PEAR_CONFIG_DEFAULT_WWW_DIR',
  9918.            $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'www');
  9919. }
  9920.  
  9921. // Default for test_dir
  9922. if (getenv('PHP_PEAR_TEST_DIR')) {
  9923.     define('PEAR_CONFIG_DEFAULT_TEST_DIR', getenv('PHP_PEAR_TEST_DIR'));
  9924. } else {
  9925.     define('PEAR_CONFIG_DEFAULT_TEST_DIR',
  9926.            $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'tests');
  9927. }
  9928.  
  9929. // Default for temp_dir
  9930. if (getenv('PHP_PEAR_TEMP_DIR')) {
  9931.     define('PEAR_CONFIG_DEFAULT_TEMP_DIR', getenv('PHP_PEAR_TEMP_DIR'));
  9932. } else {
  9933.     define('PEAR_CONFIG_DEFAULT_TEMP_DIR',
  9934.            System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' .
  9935.            DIRECTORY_SEPARATOR . 'temp');
  9936. }
  9937.  
  9938. // Default for cache_dir
  9939. if (getenv('PHP_PEAR_CACHE_DIR')) {
  9940.     define('PEAR_CONFIG_DEFAULT_CACHE_DIR', getenv('PHP_PEAR_CACHE_DIR'));
  9941. } else {
  9942.     define('PEAR_CONFIG_DEFAULT_CACHE_DIR',
  9943.            System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' .
  9944.            DIRECTORY_SEPARATOR . 'cache');
  9945. }
  9946.  
  9947. // Default for download_dir
  9948. if (getenv('PHP_PEAR_DOWNLOAD_DIR')) {
  9949.     define('PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR', getenv('PHP_PEAR_DOWNLOAD_DIR'));
  9950. } else {
  9951.     define('PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR',
  9952.            System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' .
  9953.            DIRECTORY_SEPARATOR . 'download');
  9954. }
  9955.  
  9956. // Default for php_bin
  9957. if (getenv('PHP_PEAR_PHP_BIN')) {
  9958.     define('PEAR_CONFIG_DEFAULT_PHP_BIN', getenv('PHP_PEAR_PHP_BIN'));
  9959. } else {
  9960.     define('PEAR_CONFIG_DEFAULT_PHP_BIN', PEAR_CONFIG_DEFAULT_BIN_DIR.
  9961.            DIRECTORY_SEPARATOR.'php'.(OS_WINDOWS ? '.exe' : ''));
  9962. }
  9963.  
  9964. // Default for verbose
  9965. if (getenv('PHP_PEAR_VERBOSE')) {
  9966.     define('PEAR_CONFIG_DEFAULT_VERBOSE', getenv('PHP_PEAR_VERBOSE'));
  9967. } else {
  9968.     define('PEAR_CONFIG_DEFAULT_VERBOSE', 1);
  9969. }
  9970.  
  9971. // Default for preferred_state
  9972. if (getenv('PHP_PEAR_PREFERRED_STATE')) {
  9973.     define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', getenv('PHP_PEAR_PREFERRED_STATE'));
  9974. } else {
  9975.     define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', 'stable');
  9976. }
  9977.  
  9978. // Default for umask
  9979. if (getenv('PHP_PEAR_UMASK')) {
  9980.     define('PEAR_CONFIG_DEFAULT_UMASK', getenv('PHP_PEAR_UMASK'));
  9981. } else {
  9982.     define('PEAR_CONFIG_DEFAULT_UMASK', decoct(umask()));
  9983. }
  9984.  
  9985. // Default for cache_ttl
  9986. if (getenv('PHP_PEAR_CACHE_TTL')) {
  9987.     define('PEAR_CONFIG_DEFAULT_CACHE_TTL', getenv('PHP_PEAR_CACHE_TTL'));
  9988. } else {
  9989.     define('PEAR_CONFIG_DEFAULT_CACHE_TTL', 3600);
  9990. }
  9991.  
  9992. // Default for sig_type
  9993. if (getenv('PHP_PEAR_SIG_TYPE')) {
  9994.     define('PEAR_CONFIG_DEFAULT_SIG_TYPE', getenv('PHP_PEAR_SIG_TYPE'));
  9995. } else {
  9996.     define('PEAR_CONFIG_DEFAULT_SIG_TYPE', 'gpg');
  9997. }
  9998.  
  9999. // Default for sig_bin
  10000. if (getenv('PHP_PEAR_SIG_BIN')) {
  10001.     define('PEAR_CONFIG_DEFAULT_SIG_BIN', getenv('PHP_PEAR_SIG_BIN'));
  10002. } else {
  10003.     define('PEAR_CONFIG_DEFAULT_SIG_BIN',
  10004.            System::which(
  10005.                'gpg', OS_WINDOWS ? 'c:\gnupg\gpg.exe' : '/usr/local/bin/gpg'));
  10006. }
  10007.  
  10008. // Default for sig_keydir
  10009. if (getenv('PHP_PEAR_SIG_KEYDIR')) {
  10010.     define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR', getenv('PHP_PEAR_SIG_KEYDIR'));
  10011. } else {
  10012.     define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR',
  10013.            PEAR_CONFIG_SYSCONFDIR . DIRECTORY_SEPARATOR . 'pearkeys');
  10014. }
  10015.  
  10016. /**
  10017.  * This is a class for storing configuration data, keeping track of
  10018.  * which are system-defined, user-defined or defaulted.
  10019.  * @category   pear
  10020.  * @package    PEAR
  10021.  * @author     Stig Bakken <ssb@php.net>
  10022.  * @author     Greg Beaver <cellog@php.net>
  10023.  * @copyright  1997-2008 The PHP Group
  10024.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  10025.  * @version    Release: 1.7.1
  10026.  * @link       http://pear.php.net/package/PEAR
  10027.  * @since      Class available since Release 0.1
  10028.  */
  10029. class PEAR_Config extends PEAR
  10030. {
  10031.     // {{{ properties
  10032.  
  10033.     /**
  10034.      * Array of config files used.
  10035.      *
  10036.      * @var array layer => config file
  10037.      */
  10038.     var $files = array(
  10039.         'system' => '',
  10040.         'user' => '',
  10041.         );
  10042.  
  10043.     var $layers = array();
  10044.     
  10045.     /**
  10046.      * Configuration data, two-dimensional array where the first
  10047.      * dimension is the config layer ('user', 'system' and 'default'),
  10048.      * and the second dimension is keyname => value.
  10049.      *
  10050.      * The order in the first dimension is important!  Earlier
  10051.      * layers will shadow later ones when a config value is
  10052.      * requested (if a 'user' value exists, it will be returned first,
  10053.      * then 'system' and finally 'default').
  10054.      *
  10055.      * @var array layer => array(keyname => value, ...)
  10056.      */
  10057.     var $configuration = array(
  10058.         'user' => array(),
  10059.         'system' => array(),
  10060.         'default' => array(),
  10061.         );
  10062.     
  10063.     /**
  10064.      * Configuration values that can be set for a channel
  10065.      *
  10066.      * All other configuration values can only have a global value
  10067.      * @var array
  10068.      * @access private
  10069.      */
  10070.     var $_channelConfigInfo = array(
  10071.         'php_dir', 'ext_dir', 'doc_dir', 'bin_dir', 'data_dir', 'cfg_dir',
  10072.         'test_dir', 'www_dir', 'php_bin', 'username', 'password', 'verbose',
  10073.         'preferred_state', 'umask', 'preferred_mirror',
  10074.         );
  10075.  
  10076.     /**
  10077.      * Channels that can be accessed
  10078.      * @see setChannels()
  10079.      * @var array
  10080.      * @access private
  10081.      */
  10082.     var $_channels = array('pear.php.net', 'pecl.php.net', '__uri');
  10083.  
  10084.     /**
  10085.      * This variable is used to control the directory values returned
  10086.      * @see setInstallRoot();
  10087.      * @var string|false
  10088.      * @access private
  10089.      */
  10090.     var $_installRoot = false;
  10091.  
  10092.     /**
  10093.      * If requested, this will always refer to the registry
  10094.      * contained in php_dir
  10095.      * @var PEAR_Registry
  10096.      */
  10097.     var $_registry = array();
  10098.  
  10099.     /**
  10100.      * @var array
  10101.      * @access private
  10102.      */
  10103.     var $_regInitialized = array();
  10104.  
  10105.     /**
  10106.      * @var bool
  10107.      * @access private
  10108.      */
  10109.     var $_noRegistry = false;
  10110.  
  10111.     /**
  10112.      * amount of errors found while parsing config
  10113.      * @var integer
  10114.      * @access private
  10115.      */
  10116.     var $_errorsFound = 0;
  10117.     var $_lastError = null;
  10118.  
  10119.     /**
  10120.      * Information about the configuration data.  Stores the type,
  10121.      * default value and a documentation string for each configuration
  10122.      * value.
  10123.      *
  10124.      * @var array layer => array(infotype => value, ...)
  10125.      */
  10126.     var $configuration_info = array(
  10127.         // Channels/Internet Access
  10128.         'default_channel' => array(
  10129.             'type' => 'string',
  10130.             'default' => PEAR_CONFIG_DEFAULT_CHANNEL,
  10131.             'doc' => 'the default channel to use for all non explicit commands',
  10132.             'prompt' => 'Default Channel',
  10133.             'group' => 'Internet Access',
  10134.             ),
  10135.         'preferred_mirror' => array(
  10136.             'type' => 'string',
  10137.             'default' => PEAR_CONFIG_DEFAULT_CHANNEL,
  10138.             'doc' => 'the default server or mirror to use for channel actions',
  10139.             'prompt' => 'Default Channel Mirror',
  10140.             'group' => 'Internet Access',
  10141.             ),
  10142.         'remote_config' => array(
  10143.             'type' => 'password',
  10144.             'default' => '',
  10145.             'doc' => 'ftp url of remote configuration file to use for synchronized install',
  10146.             'prompt' => 'Remote Configuration File',
  10147.             'group' => 'Internet Access',
  10148.             ),
  10149.         'auto_discover' => array(
  10150.             'type' => 'integer',
  10151.             'default' => 0,
  10152.             'doc' => 'whether to automatically discover new channels',
  10153.             'prompt' => 'Auto-discover new Channels',
  10154.             'group' => 'Internet Access',
  10155.             ),
  10156.         // Internet Access
  10157.         'master_server' => array(
  10158.             'type' => 'string',
  10159.             'default' => 'pear.php.net',
  10160.             'doc' => 'name of the main PEAR server [NOT USED IN THIS VERSION]',
  10161.             'prompt' => 'PEAR server [DEPRECATED]',
  10162.             'group' => 'Internet Access',
  10163.             ),
  10164.         'http_proxy' => array(
  10165.             'type' => 'string',
  10166.             'default' => PEAR_CONFIG_DEFAULT_HTTP_PROXY,
  10167.             'doc' => 'HTTP proxy (host:port) to use when downloading packages',
  10168.             'prompt' => 'HTTP Proxy Server Address',
  10169.             'group' => 'Internet Access',
  10170.             ),
  10171.         // File Locations
  10172.         'php_dir' => array(
  10173.             'type' => 'directory',
  10174.             'default' => PEAR_CONFIG_DEFAULT_PHP_DIR,
  10175.             'doc' => 'directory where .php files are installed',
  10176.             'prompt' => 'PEAR directory',
  10177.             'group' => 'File Locations',
  10178.             ),
  10179.         'ext_dir' => array(
  10180.             'type' => 'directory',
  10181.             'default' => PEAR_CONFIG_DEFAULT_EXT_DIR,
  10182.             'doc' => 'directory where loadable extensions are installed',
  10183.             'prompt' => 'PHP extension directory',
  10184.             'group' => 'File Locations',
  10185.             ),
  10186.         'doc_dir' => array(
  10187.             'type' => 'directory',
  10188.             'default' => PEAR_CONFIG_DEFAULT_DOC_DIR,
  10189.             'doc' => 'directory where documentation is installed',
  10190.             'prompt' => 'PEAR documentation directory',
  10191.             'group' => 'File Locations',
  10192.             ),
  10193.         'bin_dir' => array(
  10194.             'type' => 'directory',
  10195.             'default' => PEAR_CONFIG_DEFAULT_BIN_DIR,
  10196.             'doc' => 'directory where executables are installed',
  10197.             'prompt' => 'PEAR executables directory',
  10198.             'group' => 'File Locations',
  10199.             ),
  10200.         'data_dir' => array(
  10201.             'type' => 'directory',
  10202.             'default' => PEAR_CONFIG_DEFAULT_DATA_DIR,
  10203.             'doc' => 'directory where data files are installed',
  10204.             'prompt' => 'PEAR data directory',
  10205.             'group' => 'File Locations (Advanced)',
  10206.             ),
  10207.         'cfg_dir' => array(
  10208.             'type' => 'directory',
  10209.             'default' => PEAR_CONFIG_DEFAULT_CFG_DIR,
  10210.             'doc' => 'directory where modifiable configuration files are installed',
  10211.             'prompt' => 'PEAR configuration file directory',
  10212.             'group' => 'File Locations (Advanced)',
  10213.             ),
  10214.         'www_dir' => array(
  10215.             'type' => 'directory',
  10216.             'default' => PEAR_CONFIG_DEFAULT_WWW_DIR,
  10217.             'doc' => 'directory where www frontend files (html/js) are installed',
  10218.             'prompt' => 'PEAR www files directory',
  10219.             'group' => 'File Locations (Advanced)',
  10220.             ),
  10221.         'test_dir' => array(
  10222.             'type' => 'directory',
  10223.             'default' => PEAR_CONFIG_DEFAULT_TEST_DIR,
  10224.             'doc' => 'directory where regression tests are installed',
  10225.             'prompt' => 'PEAR test directory',
  10226.             'group' => 'File Locations (Advanced)',
  10227.             ),
  10228.         'cache_dir' => array(
  10229.             'type' => 'directory',
  10230.             'default' => PEAR_CONFIG_DEFAULT_CACHE_DIR,
  10231.             'doc' => 'directory which is used for XMLRPC cache',
  10232.             'prompt' => 'PEAR Installer cache directory',
  10233.             'group' => 'File Locations (Advanced)',
  10234.             ),
  10235.         'temp_dir' => array(
  10236.             'type' => 'directory',
  10237.             'default' => PEAR_CONFIG_DEFAULT_TEMP_DIR,
  10238.             'doc' => 'directory which is used for all temp files',
  10239.             'prompt' => 'PEAR Installer temp directory',
  10240.             'group' => 'File Locations (Advanced)',
  10241.             ),
  10242.         'download_dir' => array(
  10243.             'type' => 'directory',
  10244.             'default' => PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR,
  10245.             'doc' => 'directory which is used for all downloaded files',
  10246.             'prompt' => 'PEAR Installer download directory',
  10247.             'group' => 'File Locations (Advanced)',
  10248.             ),
  10249.         'php_bin' => array(
  10250.             'type' => 'file',
  10251.             'default' => PEAR_CONFIG_DEFAULT_PHP_BIN,
  10252.             'doc' => 'PHP CLI/CGI binary for executing scripts',
  10253.             'prompt' => 'PHP CLI/CGI binary',
  10254.             'group' => 'File Locations (Advanced)',
  10255.             ),
  10256.         'php_ini' => array(
  10257.             'type' => 'file',
  10258.             'default' => '',
  10259.             'doc' => 'location of php.ini in which to enable PECL extensions on install',
  10260.             'prompt' => 'php.ini location',
  10261.             'group' => 'File Locations (Advanced)',
  10262.             ),
  10263.         // Maintainers
  10264.         'username' => array(
  10265.             'type' => 'string',
  10266.             'default' => '',
  10267.             'doc' => '(maintainers) your PEAR account name',
  10268.             'prompt' => 'PEAR username (for maintainers)',
  10269.             'group' => 'Maintainers',
  10270.             ),
  10271.         'password' => array(
  10272.             'type' => 'password',
  10273.             'default' => '',
  10274.             'doc' => '(maintainers) your PEAR account password',
  10275.             'prompt' => 'PEAR password (for maintainers)',
  10276.             'group' => 'Maintainers',
  10277.             ),
  10278.         // Advanced
  10279.         'verbose' => array(
  10280.             'type' => 'integer',
  10281.             'default' => PEAR_CONFIG_DEFAULT_VERBOSE,
  10282.             'doc' => 'verbosity level
  10283. 0: really quiet
  10284. 1: somewhat quiet
  10285. 2: verbose
  10286. 3: debug',
  10287.             'prompt' => 'Debug Log Level',
  10288.             'group' => 'Advanced',
  10289.             ),
  10290.         'preferred_state' => array(
  10291.             'type' => 'set',
  10292.             'default' => PEAR_CONFIG_DEFAULT_PREFERRED_STATE,
  10293.             'doc' => 'the installer will prefer releases with this state when installing packages without a version or state specified',
  10294.             'valid_set' => array(
  10295.                 'stable', 'beta', 'alpha', 'devel', 'snapshot'),
  10296.             'prompt' => 'Preferred Package State',
  10297.             'group' => 'Advanced',
  10298.             ),
  10299.         'umask' => array(
  10300.             'type' => 'mask',
  10301.             'default' => PEAR_CONFIG_DEFAULT_UMASK,
  10302.             'doc' => 'umask used when creating files (Unix-like systems only)',
  10303.             'prompt' => 'Unix file mask',
  10304.             'group' => 'Advanced',
  10305.             ),
  10306.         'cache_ttl' => array(
  10307.             'type' => 'integer',
  10308.             'default' => PEAR_CONFIG_DEFAULT_CACHE_TTL,
  10309.             'doc' => 'amount of secs where the local cache is used and not updated',
  10310.             'prompt' => 'Cache TimeToLive',
  10311.             'group' => 'Advanced',
  10312.             ),
  10313.         'sig_type' => array(
  10314.             'type' => 'set',
  10315.             'default' => PEAR_CONFIG_DEFAULT_SIG_TYPE,
  10316.             'doc' => 'which package signature mechanism to use',
  10317.             'valid_set' => array('gpg'),
  10318.             'prompt' => 'Package Signature Type',
  10319.             'group' => 'Maintainers',
  10320.             ),
  10321.         'sig_bin' => array(
  10322.             'type' => 'string',
  10323.             'default' => PEAR_CONFIG_DEFAULT_SIG_BIN,
  10324.             'doc' => 'which package signature mechanism to use',
  10325.             'prompt' => 'Signature Handling Program',
  10326.             'group' => 'Maintainers',
  10327.             ),
  10328.         'sig_keyid' => array(
  10329.             'type' => 'string',
  10330.             'default' => '',
  10331.             'doc' => 'which key to use for signing with',
  10332.             'prompt' => 'Signature Key Id',
  10333.             'group' => 'Maintainers',
  10334.             ),
  10335.         'sig_keydir' => array(
  10336.             'type' => 'directory',
  10337.             'default' => PEAR_CONFIG_DEFAULT_SIG_KEYDIR,
  10338.             'doc' => 'directory where signature keys are located',
  10339.             'prompt' => 'Signature Key Directory',
  10340.             'group' => 'Maintainers',
  10341.             ),
  10342.         // __channels is reserved - used for channel-specific configuration
  10343.         );
  10344.  
  10345.     // }}}
  10346.  
  10347.     // {{{ PEAR_Config([file], [defaults_file])
  10348.  
  10349.     /**
  10350.      * Constructor.
  10351.      *
  10352.      * @param string file to read user-defined options from
  10353.      * @param string file to read system-wide defaults from
  10354.      * @param bool   determines whether a registry object "follows"
  10355.      *               the value of php_dir (is automatically created
  10356.      *               and moved when php_dir is changed)
  10357.      * @param bool   if true, fails if configuration files cannot be loaded
  10358.      *
  10359.      * @access public
  10360.      *
  10361.      * @see PEAR_Config::singleton
  10362.      */
  10363.     function PEAR_Config($user_file = '', $system_file = '', $ftp_file = false,
  10364.                          $strict = true)
  10365.     {
  10366.         $this->PEAR();
  10367.         PEAR_Installer_Role::initializeConfig($this);
  10368.         $sl = DIRECTORY_SEPARATOR;
  10369.         if (empty($user_file)) {
  10370.             if (OS_WINDOWS) {
  10371.                 $user_file = PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.ini';
  10372.             } else {
  10373.                 $user_file = getenv('HOME') . $sl . '.pearrc';
  10374.             }
  10375.         }
  10376.         if (empty($system_file)) {
  10377.             if (OS_WINDOWS) {
  10378.                 $system_file = PEAR_CONFIG_SYSCONFDIR . $sl . 'pearsys.ini';
  10379.             } else {
  10380.                 $system_file = PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.conf';
  10381.             }
  10382.         }
  10383.  
  10384.         $this->layers = array_keys($this->configuration);
  10385.         $this->files['user'] = $user_file;
  10386.         $this->files['system'] = $system_file;
  10387.         if ($user_file && file_exists($user_file)) {
  10388.             $this->pushErrorHandling(PEAR_ERROR_RETURN);
  10389.             $this->readConfigFile($user_file, 'user', $strict);
  10390.             $this->popErrorHandling();
  10391.             if ($this->_errorsFound > 0) {
  10392.                 return;
  10393.             }
  10394.         }
  10395.  
  10396.         if ($system_file && file_exists($system_file)) {
  10397.             $this->mergeConfigFile($system_file, false, 'system', $strict);
  10398.             if ($this->_errorsFound > 0) {
  10399.                 return;
  10400.             }
  10401.  
  10402.         }
  10403.  
  10404.         if (!$ftp_file) {
  10405.             $ftp_file = $this->get('remote_config');
  10406.         }
  10407.  
  10408.         if ($ftp_file && defined('PEAR_REMOTEINSTALL_OK')) {
  10409.             $this->readFTPConfigFile($ftp_file);
  10410.         }
  10411.  
  10412.         foreach ($this->configuration_info as $key => $info) {
  10413.             $this->configuration['default'][$key] = $info['default'];
  10414.         }
  10415.  
  10416.         $this->_registry['default'] = &new PEAR_Registry($this->configuration['default']['php_dir']);
  10417.         $this->_registry['default']->setConfig($this);
  10418.         $this->_regInitialized['default'] = false;
  10419.         //$GLOBALS['_PEAR_Config_instance'] = &$this;
  10420.     }
  10421.  
  10422.     // }}}
  10423.     /**
  10424.      * Return the default locations of user and system configuration files
  10425.      * @static
  10426.      */
  10427.     function getDefaultConfigFiles()
  10428.     {
  10429.         $sl = DIRECTORY_SEPARATOR;
  10430.         if (OS_WINDOWS) {
  10431.             return array(
  10432.                 'user' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.ini',
  10433.                 'system' =>  PEAR_CONFIG_SYSCONFDIR . $sl . 'pearsys.ini'
  10434.             );
  10435.         } else {
  10436.             return array(
  10437.                 'user' => getenv('HOME') . $sl . '.pearrc',
  10438.                 'system' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.conf'
  10439.             );
  10440.         }
  10441.     }
  10442.     // {{{ singleton([file], [defaults_file])
  10443.  
  10444.     /**
  10445.      * Static singleton method.  If you want to keep only one instance
  10446.      * of this class in use, this method will give you a reference to
  10447.      * the last created PEAR_Config object if one exists, or create a
  10448.      * new object.
  10449.      *
  10450.      * @param string (optional) file to read user-defined options from
  10451.      * @param string (optional) file to read system-wide defaults from
  10452.      *
  10453.      * @return object an existing or new PEAR_Config instance
  10454.      *
  10455.      * @access public
  10456.      *
  10457.      * @see PEAR_Config::PEAR_Config
  10458.      */
  10459.     function &singleton($user_file = '', $system_file = '', $strict = true)
  10460.     {
  10461.         if (is_object($GLOBALS['_PEAR_Config_instance'])) {
  10462.             return $GLOBALS['_PEAR_Config_instance'];
  10463.         }
  10464.  
  10465.         $t_conf = &new PEAR_Config($user_file, $system_file, false, $strict);
  10466.         if ($t_conf->_errorsFound > 0) {
  10467.              return $t_conf->lastError;
  10468.         }
  10469.  
  10470.         $GLOBALS['_PEAR_Config_instance'] = &$t_conf;
  10471.         return $GLOBALS['_PEAR_Config_instance'];
  10472.     }
  10473.  
  10474.     // }}}
  10475.     // {{{ validConfiguration()
  10476.  
  10477.     /**
  10478.      * Determine whether any configuration files have been detected, and whether a
  10479.      * registry object can be retrieved from this configuration.
  10480.      * @return bool
  10481.      * @since PEAR 1.4.0a1
  10482.      */
  10483.     function validConfiguration()
  10484.     {
  10485.         if ($this->isDefinedLayer('user') || $this->isDefinedLayer('system')) {
  10486.             return true;
  10487.         }
  10488.         return false;
  10489.     }
  10490.  
  10491.     // }}}
  10492.     // {{{ readConfigFile([file], [layer])
  10493.  
  10494.     /**
  10495.      * Reads configuration data from a file.  All existing values in
  10496.      * the config layer are discarded and replaced with data from the
  10497.      * file.
  10498.      * @param string file to read from, if NULL or not specified, the
  10499.      *               last-used file for the same layer (second param) is used
  10500.      * @param string config layer to insert data into ('user' or 'system')
  10501.      * @return bool TRUE on success or a PEAR error on failure
  10502.      */
  10503.     function readConfigFile($file = null, $layer = 'user', $strict = true)
  10504.     {
  10505.         if (empty($this->files[$layer])) {
  10506.             return $this->raiseError("unknown config layer `$layer'");
  10507.         }
  10508.  
  10509.         if ($file === null) {
  10510.             $file = $this->files[$layer];
  10511.         }
  10512.  
  10513.         $data = $this->_readConfigDataFrom($file);
  10514.  
  10515.         if (PEAR::isError($data)) {
  10516.             if ($strict) {
  10517.                 $this->_errorsFound++;
  10518.                 $this->lastError = $data;
  10519.  
  10520.                 return $data;
  10521.             } else {
  10522.                 return true;
  10523.             }
  10524.         } else {
  10525.             $this->files[$layer] = $file;
  10526.         }
  10527.  
  10528.         $this->_decodeInput($data);
  10529.         $this->configuration[$layer] = $data;
  10530.         $this->_setupChannels();
  10531.         if (!$this->_noRegistry && ($phpdir = $this->get('php_dir', $layer, 'pear.php.net'))) {
  10532.             $this->_registry[$layer] = &new PEAR_Registry($phpdir);
  10533.             $this->_registry[$layer]->setConfig($this);
  10534.             $this->_regInitialized[$layer] = false;
  10535.         } else {
  10536.             unset($this->_registry[$layer]);
  10537.         }
  10538.         return true;
  10539.     }
  10540.  
  10541.     // }}}
  10542.  
  10543.     /**
  10544.      * @param string url to the remote config file, like ftp://www.example.com/pear/config.ini
  10545.      * @return true|PEAR_Error
  10546.      */
  10547.     function readFTPConfigFile($path)
  10548.     {
  10549.         do { // poor man's try
  10550.             if (!class_exists('PEAR_FTP')) {
  10551.                 if (!class_exists('PEAR_Common')) {
  10552.                     require_once 'phar://go-pear.phar/' . 'PEAR/Common.php';
  10553.                 }
  10554.                 if (PEAR_Common::isIncludeable('PEAR/FTP.php')) {
  10555.                     require_once 'phar://go-pear.phar/' . 'PEAR/FTP.php';
  10556.                 }
  10557.             }
  10558.             if (class_exists('PEAR_FTP')) {
  10559.                 $this->_ftp = &new PEAR_FTP;
  10560.                 $this->_ftp->pushErrorHandling(PEAR_ERROR_RETURN);
  10561.                 $e = $this->_ftp->init($path);
  10562.                 if (PEAR::isError($e)) {
  10563.                     $this->_ftp->popErrorHandling();
  10564.                     return $e;
  10565.                 }
  10566.                 $tmp = System::mktemp('-d');
  10567.                 PEAR_Common::addTempFile($tmp);
  10568.                 $e = $this->_ftp->get(basename($path), $tmp . DIRECTORY_SEPARATOR .
  10569.                     'pear.ini', false, FTP_BINARY);
  10570.                 if (PEAR::isError($e)) {
  10571.                     $this->_ftp->popErrorHandling();
  10572.                     return $e;
  10573.                 }
  10574.                 PEAR_Common::addTempFile($tmp . DIRECTORY_SEPARATOR . 'pear.ini');
  10575.                 $this->_ftp->disconnect();
  10576.                 $this->_ftp->popErrorHandling();
  10577.                 $this->files['ftp'] = $tmp . DIRECTORY_SEPARATOR . 'pear.ini';
  10578.                 $e = $this->readConfigFile(null, 'ftp');
  10579.                 if (PEAR::isError($e)) {
  10580.                     return $e;
  10581.                 }
  10582.                 $fail = array();
  10583.                 foreach ($this->configuration_info as $key => $val) {
  10584.                     if (in_array($this->getGroup($key),
  10585.                           array('File Locations', 'File Locations (Advanced)')) &&
  10586.                           $this->getType($key) == 'directory') {
  10587.                         // any directory configs must be set for this to work
  10588.                         if (!isset($this->configuration['ftp'][$key])) {
  10589.                             $fail[] = $key;
  10590.                         }
  10591.                     }
  10592.                 }
  10593.                 if (count($fail)) {
  10594.                     $fail = '"' . implode('", "', $fail) . '"';
  10595.                     unset($this->files['ftp']);
  10596.                     unset($this->configuration['ftp']);
  10597.                     return PEAR::raiseError('ERROR: Ftp configuration file must set all ' .
  10598.                         'directory configuration variables.  These variables were not set: ' .
  10599.                         $fail);
  10600.                 } else {
  10601.                     return true;
  10602.                 }
  10603.             } else {
  10604.                 return PEAR::raiseError('PEAR_RemoteInstaller must be installed to use remote config');
  10605.             }
  10606.         } while (false); // poor man's catch
  10607.         unset($this->files['ftp']);
  10608.         return PEAR::raiseError('no remote host specified');
  10609.     }
  10610.  
  10611.     // {{{ _setupChannels()
  10612.     
  10613.     /**
  10614.      * Reads the existing configurations and creates the _channels array from it
  10615.      */
  10616.     function _setupChannels()
  10617.     {
  10618.         $set = array_flip(array_values($this->_channels));
  10619.         foreach ($this->configuration as $layer => $data) {
  10620.             $i = 1000;
  10621.             if (isset($data['__channels']) && is_array($data['__channels'])) {
  10622.                 foreach ($data['__channels'] as $channel => $info) {
  10623.                     $set[$channel] = $i++;
  10624.                 }
  10625.             }
  10626.         }
  10627.         $this->_channels = array_values(array_flip($set));
  10628.         $this->setChannels($this->_channels);
  10629.     }
  10630.  
  10631.     // }}}
  10632.     // {{{ deleteChannel(channel)
  10633.  
  10634.     function deleteChannel($channel)
  10635.     {
  10636.         foreach ($this->configuration as $layer => $data) {
  10637.             if (isset($data['__channels'])) {
  10638.                 if (isset($data['__channels'][strtolower($channel)])) {
  10639.                     unset($this->configuration[$layer]['__channels'][strtolower($channel)]);
  10640.                 }
  10641.             }
  10642.         }
  10643.         $this->_channels = array_flip($this->_channels);
  10644.         unset($this->_channels[strtolower($channel)]);
  10645.         $this->_channels = array_flip($this->_channels);
  10646.     }
  10647.  
  10648.     // }}}
  10649.     // {{{ mergeConfigFile(file, [override], [layer])
  10650.  
  10651.     /**
  10652.      * Merges data into a config layer from a file.  Does the same
  10653.      * thing as readConfigFile, except it does not replace all
  10654.      * existing values in the config layer.
  10655.      * @param string file to read from
  10656.      * @param bool whether to overwrite existing data (default TRUE)
  10657.      * @param string config layer to insert data into ('user' or 'system')
  10658.      * @param string if true, errors are returned if file opening fails
  10659.      * @return bool TRUE on success or a PEAR error on failure
  10660.      */
  10661.     function mergeConfigFile($file, $override = true, $layer = 'user', $strict = true)
  10662.     {
  10663.         if (empty($this->files[$layer])) {
  10664.             return $this->raiseError("unknown config layer `$layer'");
  10665.         }
  10666.         if ($file === null) {
  10667.             $file = $this->files[$layer];
  10668.         }
  10669.         $data = $this->_readConfigDataFrom($file);
  10670.         if (PEAR::isError($data)) {
  10671.             if ($strict) {
  10672.                 $this->_errorsFound++;
  10673.                 $this->lastError = $data;
  10674.  
  10675.                 return $data;
  10676.             } else {
  10677.                 return true;
  10678.             }
  10679.         }
  10680.         $this->_decodeInput($data);
  10681.         if ($override) {
  10682.             $this->configuration[$layer] =
  10683.                 PEAR_Config::arrayMergeRecursive($this->configuration[$layer], $data);
  10684.         } else {
  10685.             $this->configuration[$layer] =
  10686.                 PEAR_Config::arrayMergeRecursive($data, $this->configuration[$layer]);
  10687.         }
  10688.         $this->_setupChannels();
  10689.         if (!$this->_noRegistry && ($phpdir = $this->get('php_dir', $layer, 'pear.php.net'))) {
  10690.             $this->_registry[$layer] = &new PEAR_Registry($phpdir);
  10691.             $this->_registry[$layer]->setConfig($this);
  10692.             $this->_regInitialized[$layer] = false;
  10693.         } else {
  10694.             unset($this->_registry[$layer]);
  10695.         }
  10696.         return true;
  10697.     }
  10698.  
  10699.     // }}}
  10700.     // {{{ arrayMergeRecursive($arr2, $arr1)
  10701.     /**
  10702.      * @param array
  10703.      * @param array
  10704.      * @return array
  10705.      * @static
  10706.      */
  10707.     function arrayMergeRecursive($arr2, $arr1)
  10708.     {
  10709.         $ret = array();
  10710.         foreach ($arr2 as $key => $data) {
  10711.             if (!isset($arr1[$key])) {
  10712.                 $ret[$key] = $data;
  10713.                 unset($arr1[$key]);
  10714.                 continue;
  10715.             }
  10716.             if (is_array($data)) {
  10717.                 if (!is_array($arr1[$key])) {
  10718.                     $ret[$key] = $arr1[$key];
  10719.                     unset($arr1[$key]);
  10720.                     continue;
  10721.                 }
  10722.                 $ret[$key] = PEAR_Config::arrayMergeRecursive($arr1[$key], $arr2[$key]);
  10723.                 unset($arr1[$key]);
  10724.             }
  10725.         }
  10726.         return array_merge($ret, $arr1);
  10727.     }
  10728.  
  10729.     // }}}
  10730.     // {{{ writeConfigFile([file], [layer])
  10731.  
  10732.     /**
  10733.      * Writes data into a config layer from a file.
  10734.      *
  10735.      * @param string|null file to read from, or null for default
  10736.      * @param string config layer to insert data into ('user' or
  10737.      *               'system')
  10738.      * @param string|null data to write to config file or null for internal data [DEPRECATED]
  10739.      * @return bool TRUE on success or a PEAR error on failure
  10740.      */
  10741.     function writeConfigFile($file = null, $layer = 'user', $data = null)
  10742.     {
  10743.         $this->_lazyChannelSetup($layer);
  10744.         if ($layer == 'both' || $layer == 'all') {
  10745.             foreach ($this->files as $type => $file) {
  10746.                 $err = $this->writeConfigFile($file, $type, $data);
  10747.                 if (PEAR::isError($err)) {
  10748.                     return $err;
  10749.                 }
  10750.             }
  10751.             return true;
  10752.         }
  10753.         if (empty($this->files[$layer])) {
  10754.             return $this->raiseError("unknown config file type `$layer'");
  10755.         }
  10756.         if ($file === null) {
  10757.             $file = $this->files[$layer];
  10758.         }
  10759.         $data = ($data === null) ? $this->configuration[$layer] : $data;
  10760.         $this->_encodeOutput($data);
  10761.         $opt = array('-p', dirname($file));
  10762.         if (!@System::mkDir($opt)) {
  10763.             return $this->raiseError("could not create directory: " . dirname($file));
  10764.         }
  10765.         if (file_exists($file) && is_file($file) && !is_writeable($file)) {
  10766.             return $this->raiseError("no write access to $file!");
  10767.         }
  10768.         $fp = @fopen($file, "w");
  10769.         if (!$fp) {
  10770.             return $this->raiseError("PEAR_Config::writeConfigFile fopen('$file','w') failed ($php_errormsg)");
  10771.         }
  10772.         $contents = "#PEAR_Config 0.9\n" . serialize($data);
  10773.         if (!@fwrite($fp, $contents)) {
  10774.             return $this->raiseError("PEAR_Config::writeConfigFile: fwrite failed ($php_errormsg)");
  10775.         }
  10776.         return true;
  10777.     }
  10778.  
  10779.     // }}}
  10780.     // {{{ _readConfigDataFrom(file)
  10781.  
  10782.     /**
  10783.      * Reads configuration data from a file and returns the parsed data
  10784.      * in an array.
  10785.      *
  10786.      * @param string file to read from
  10787.      *
  10788.      * @return array configuration data or a PEAR error on failure
  10789.      *
  10790.      * @access private
  10791.      */
  10792.     function _readConfigDataFrom($file)
  10793.     {
  10794.         $fp = false;
  10795.         if (file_exists($file)) {
  10796.             $fp = @fopen($file, "r");
  10797.         }
  10798.         if (!$fp) {
  10799.             return $this->raiseError("PEAR_Config::readConfigFile fopen('$file','r') failed");
  10800.         }
  10801.         $size = filesize($file);
  10802.         $rt = get_magic_quotes_runtime();
  10803.         set_magic_quotes_runtime(0);
  10804.         fclose($fp);
  10805.         $contents = file_get_contents($file);
  10806.         if (empty($contents)) {
  10807.             return $this->raiseError('Configuration file "' . $file . '" is empty');
  10808.         }
  10809.         
  10810.         set_magic_quotes_runtime($rt);
  10811.  
  10812.         $version = false;
  10813.         if (preg_match('/^#PEAR_Config\s+(\S+)\s+/si', $contents, $matches)) {
  10814.             $version = $matches[1];
  10815.             $contents = substr($contents, strlen($matches[0]));
  10816.         } else {
  10817.             // Museum config file
  10818.             if (substr($contents,0,2) == 'a:') {
  10819.                 $version = '0.1';
  10820.             }
  10821.         }
  10822.         if ($version && version_compare("$version", '1', '<')) {
  10823.  
  10824.             // no '@', it is possible that unserialize
  10825.             // raises a notice but it seems to block IO to
  10826.             // STDOUT if a '@' is used and a notice is raise
  10827.             $data = unserialize($contents);
  10828.  
  10829.             if (!is_array($data) && !$data) {
  10830.                 if ($contents == serialize(false)) {
  10831.                     $data = array();
  10832.                 } else {
  10833.                     $err = $this->raiseError("PEAR_Config: bad data in $file");
  10834.                     return $err;
  10835.                 }
  10836.             }
  10837.             if (!is_array($data)) {
  10838.                 if (strlen(trim($contents)) > 0) {
  10839.                     $error = "PEAR_Config: bad data in $file";
  10840.                     $err = $this->raiseError($error);
  10841.                     return $err;
  10842.                 } else {
  10843.                     $data = array();
  10844.                 }
  10845.             }
  10846.         // add parsing of newer formats here...
  10847.         } else {
  10848.             $err = $this->raiseError("$file: unknown version `$version'");
  10849.             return $err; 
  10850.         }
  10851.         return $data;
  10852.     }
  10853.  
  10854.     // }}}
  10855.     // {{{ getConfFile(layer)
  10856.     /**
  10857.     * Gets the file used for storing the config for a layer
  10858.     *
  10859.     * @param string $layer 'user' or 'system'
  10860.     */
  10861.  
  10862.     function getConfFile($layer)
  10863.     {
  10864.         return $this->files[$layer];
  10865.     }
  10866.  
  10867.     // }}}
  10868.  
  10869.     /**
  10870.      * @param string Configuration class name, used for detecting duplicate calls
  10871.      * @param array information on a role as parsed from its xml file
  10872.      * @return true|PEAR_Error
  10873.      * @access private
  10874.      */
  10875.     function _addConfigVars($class, $vars)
  10876.     {
  10877.         static $called = array();
  10878.         if (isset($called[$class])) {
  10879.             return;
  10880.         }
  10881.         $called[$class] = 1;
  10882.         if (count($vars) > 3) {
  10883.             return $this->raiseError('Roles can only define 3 new config variables or less');
  10884.         }
  10885.         foreach ($vars as $name => $var) {
  10886.             if (!is_array($var)) {
  10887.                 return $this->raiseError('Configuration information must be an array');
  10888.             }
  10889.             if (!isset($var['type'])) {
  10890.                 return $this->raiseError('Configuration information must contain a type');
  10891.             } else {
  10892.                 if (!in_array($var['type'],
  10893.                       array('string', 'mask', 'password', 'directory', 'file', 'set'))) {
  10894.                     return $this->raiseError(
  10895.                         'Configuration type must be one of directory, file, string, ' .
  10896.                         'mask, set, or password');
  10897.                 }
  10898.             }
  10899.             if (!isset($var['default'])) {
  10900.                 return $this->raiseError(
  10901.                     'Configuration information must contain a default value ("default" index)');
  10902.             } else {
  10903.                 if (is_array($var['default'])) {
  10904.                     $real_default = '';
  10905.                     foreach ($var['default'] as $config_var => $val) {
  10906.                         if (strpos($config_var, 'text') === 0) {
  10907.                             $real_default .= $val;
  10908.                         } elseif (strpos($config_var, 'constant') === 0) {
  10909.                             if (defined($val)) {
  10910.                                 $real_default .= constant($val);
  10911.                             } else {
  10912.                                 return $this->raiseError(
  10913.                                     'Unknown constant "' . $val . '" requested in ' .
  10914.                                     'default value for configuration variable "' .
  10915.                                     $name . '"');
  10916.                             }
  10917.                         } elseif (isset($this->configuration_info[$config_var])) {
  10918.                             $real_default .=
  10919.                                 $this->configuration_info[$config_var]['default'];
  10920.                         } else {
  10921.                             return $this->raiseError(
  10922.                                 'Unknown request for "' . $config_var . '" value in ' .
  10923.                                 'default value for configuration variable "' .
  10924.                                 $name . '"');
  10925.                         }
  10926.                     }
  10927.                     $var['default'] = $real_default;
  10928.                 }
  10929.                 if ($var['type'] == 'integer') {
  10930.                     $var['default'] = (integer) $var['default'];
  10931.                 }
  10932.             }
  10933.             if (!isset($var['doc'])) {
  10934.                 return $this->raiseError(
  10935.                     'Configuration information must contain a summary ("doc" index)');
  10936.             }
  10937.             if (!isset($var['prompt'])) {
  10938.                 return $this->raiseError(
  10939.                     'Configuration information must contain a simple prompt ("prompt" index)');
  10940.             }
  10941.             if (!isset($var['group'])) {
  10942.                 return $this->raiseError(
  10943.                     'Configuration information must contain a simple group ("group" index)');
  10944.             }
  10945.             if (isset($this->configuration_info[$name])) {
  10946.                 return $this->raiseError('Configuration variable "' . $name .
  10947.                     '" already exists');
  10948.             }
  10949.             $this->configuration_info[$name] = $var;
  10950.             // fix bug #7351: setting custom config variable in a channel fails
  10951.             $this->_channelConfigInfo[] = $name;
  10952.         }
  10953.         return true;
  10954.     }
  10955.  
  10956.     // {{{ _encodeOutput(&data)
  10957.  
  10958.     /**
  10959.      * Encodes/scrambles configuration data before writing to files.
  10960.      * Currently, 'password' values will be base64-encoded as to avoid
  10961.      * that people spot cleartext passwords by accident.
  10962.      *
  10963.      * @param array (reference) array to encode values in
  10964.      *
  10965.      * @return bool TRUE on success
  10966.      *
  10967.      * @access private
  10968.      */
  10969.     function _encodeOutput(&$data)
  10970.     {
  10971.         foreach ($data as $key => $value) {
  10972.             if ($key == '__channels') {
  10973.                 foreach ($data['__channels'] as $channel => $blah) {
  10974.                     $this->_encodeOutput($data['__channels'][$channel]);
  10975.                 }
  10976.             }
  10977.             if (!isset($this->configuration_info[$key])) {
  10978.                 continue;
  10979.             }
  10980.             $type = $this->configuration_info[$key]['type'];
  10981.             switch ($type) {
  10982.                 // we base64-encode passwords so they are at least
  10983.                 // not shown in plain by accident
  10984.                 case 'password': {
  10985.                     $data[$key] = base64_encode($data[$key]);
  10986.                     break;
  10987.                 }
  10988.                 case 'mask': {
  10989.                     $data[$key] = octdec($data[$key]);
  10990.                     break;
  10991.                 }
  10992.             }
  10993.         }
  10994.         return true;
  10995.     }
  10996.  
  10997.     // }}}
  10998.     // {{{ _decodeInput(&data)
  10999.  
  11000.     /**
  11001.      * Decodes/unscrambles configuration data after reading from files.
  11002.      *
  11003.      * @param array (reference) array to encode values in
  11004.      *
  11005.      * @return bool TRUE on success
  11006.      *
  11007.      * @access private
  11008.      *
  11009.      * @see PEAR_Config::_encodeOutput
  11010.      */
  11011.     function _decodeInput(&$data)
  11012.     {
  11013.         if (!is_array($data)) {
  11014.             return true;
  11015.         }
  11016.         foreach ($data as $key => $value) {
  11017.             if ($key == '__channels') {
  11018.                 foreach ($data['__channels'] as $channel => $blah) {
  11019.                     $this->_decodeInput($data['__channels'][$channel]);
  11020.                 }
  11021.             }
  11022.             if (!isset($this->configuration_info[$key])) {
  11023.                 continue;
  11024.             }
  11025.             $type = $this->configuration_info[$key]['type'];
  11026.             switch ($type) {
  11027.                 case 'password': {
  11028.                     $data[$key] = base64_decode($data[$key]);
  11029.                     break;
  11030.                 }
  11031.                 case 'mask': {
  11032.                     $data[$key] = decoct($data[$key]);
  11033.                     break;
  11034.                 }
  11035.             }
  11036.         }
  11037.         return true;
  11038.     }
  11039.  
  11040.     // }}}
  11041.     // {{{ getDefaultChannel([layer])
  11042.     /**
  11043.      * Retrieve the default channel.
  11044.      *
  11045.      * On startup, channels are not initialized, so if the default channel is not
  11046.      * pear.php.net, then initialize the config.
  11047.      * @param string registry layer
  11048.      * @return string|false
  11049.      */
  11050.     function getDefaultChannel($layer = null)
  11051.     {
  11052.         $ret = false;
  11053.         if ($layer === null) {
  11054.             foreach ($this->layers as $layer) {
  11055.                 if (isset($this->configuration[$layer]['default_channel'])) {
  11056.                     $ret = $this->configuration[$layer]['default_channel'];
  11057.                     break;
  11058.                 }
  11059.             }
  11060.         } elseif (isset($this->configuration[$layer]['default_channel'])) {
  11061.             $ret = $this->configuration[$layer]['default_channel'];
  11062.         }
  11063.         if ($ret == 'pear.php.net' && defined('PEAR_RUNTYPE') && PEAR_RUNTYPE == 'pecl') {
  11064.             $ret = 'pecl.php.net';
  11065.         }
  11066.         if ($ret) {
  11067.             if ($ret != 'pear.php.net') {
  11068.                 $this->_lazyChannelSetup();
  11069.             }
  11070.             return $ret;
  11071.         }
  11072.         return PEAR_CONFIG_DEFAULT_CHANNEL;
  11073.     }
  11074.  
  11075.     // {{{ get(key, [layer])
  11076.     /**
  11077.      * Returns a configuration value, prioritizing layers as per the
  11078.      * layers property.
  11079.      *
  11080.      * @param string config key
  11081.      *
  11082.      * @return mixed the config value, or NULL if not found
  11083.      *
  11084.      * @access public
  11085.      */
  11086.     function get($key, $layer = null, $channel = false)
  11087.     {
  11088.         if (!isset($this->configuration_info[$key])) {
  11089.             return null;
  11090.         }
  11091.         if ($key == '__channels') {
  11092.             return null;
  11093.         }
  11094.         if ($key == 'default_channel') {
  11095.             return $this->getDefaultChannel($layer);
  11096.         }
  11097.         if (!$channel) {
  11098.             $channel = $this->getDefaultChannel();
  11099.         } elseif ($channel != 'pear.php.net') {
  11100.             $this->_lazyChannelSetup();
  11101.         }
  11102.         $channel = strtolower($channel);
  11103.         
  11104.         $test = (in_array($key, $this->_channelConfigInfo)) ?
  11105.             $this->_getChannelValue($key, $layer, $channel) :
  11106.             null;
  11107.         if ($test !== null) {
  11108.             if ($this->_installRoot) {
  11109.                 if (in_array($this->getGroup($key),
  11110.                       array('File Locations', 'File Locations (Advanced)')) &&
  11111.                       $this->getType($key) == 'directory') {
  11112.                     return $this->_prependPath($test, $this->_installRoot);
  11113.                 }
  11114.             }
  11115.             return $test;
  11116.         }
  11117.         if ($layer === null) {
  11118.             foreach ($this->layers as $layer) {
  11119.                 if (isset($this->configuration[$layer][$key])) {
  11120.                     $test = $this->configuration[$layer][$key];
  11121.                     if ($this->_installRoot) {
  11122.                         if (in_array($this->getGroup($key),
  11123.                               array('File Locations', 'File Locations (Advanced)')) &&
  11124.                               $this->getType($key) == 'directory') {
  11125.                             return $this->_prependPath($test, $this->_installRoot);
  11126.                         }
  11127.                     }
  11128.                     if ($key == 'preferred_mirror') {
  11129.                         $reg = &$this->getRegistry();
  11130.                         if (is_object($reg)) {
  11131.                             $chan = &$reg->getChannel($channel);
  11132.                             if (PEAR::isError($chan)) {
  11133.                                 return $channel;
  11134.                             }
  11135.                             if (!$chan->getMirror($test) && $chan->getName() != $test) {
  11136.                                 return $channel; // mirror does not exist
  11137.                             }
  11138.                         }
  11139.                     }
  11140.                     return $test;
  11141.                 }
  11142.             }
  11143.         } elseif (isset($this->configuration[$layer][$key])) {
  11144.             $test = $this->configuration[$layer][$key];
  11145.             if ($this->_installRoot) {
  11146.                 if (in_array($this->getGroup($key),
  11147.                       array('File Locations', 'File Locations (Advanced)')) &&
  11148.                       $this->getType($key) == 'directory') {
  11149.                     return $this->_prependPath($test, $this->_installRoot);
  11150.                 }
  11151.             }
  11152.             if ($key == 'preferred_mirror') {
  11153.                 $reg = &$this->getRegistry();
  11154.                 if (is_object($reg)) {
  11155.                     $chan = &$reg->getChannel($channel);
  11156.                     if (PEAR::isError($chan)) {
  11157.                         return $channel;
  11158.                     }
  11159.                     if (!$chan->getMirror($test) && $chan->getName() != $test) {
  11160.                         return $channel; // mirror does not exist
  11161.                     }
  11162.                 }
  11163.             }
  11164.             return $test;
  11165.         }
  11166.         return null;
  11167.     }
  11168.  
  11169.     // }}}
  11170.     // {{{ _getChannelValue(key, value, [layer])
  11171.     /**
  11172.      * Returns a channel-specific configuration value, prioritizing layers as per the
  11173.      * layers property.
  11174.      *
  11175.      * @param string config key
  11176.      *
  11177.      * @return mixed the config value, or NULL if not found
  11178.      *
  11179.      * @access private
  11180.      */
  11181.     function _getChannelValue($key, $layer, $channel)
  11182.     {
  11183.         if ($key == '__channels' || $channel == 'pear.php.net') {
  11184.             return null;
  11185.         }
  11186.         $ret = null;
  11187.         if ($layer === null) {
  11188.             foreach ($this->layers as $ilayer) {
  11189.                 if (isset($this->configuration[$ilayer]['__channels'][$channel][$key])) {
  11190.                     $ret = $this->configuration[$ilayer]['__channels'][$channel][$key];
  11191.                     break;
  11192.                 }
  11193.             }
  11194.         } elseif (isset($this->configuration[$layer]['__channels'][$channel][$key])) {
  11195.             $ret = $this->configuration[$layer]['__channels'][$channel][$key];
  11196.         }
  11197.         if ($key == 'preferred_mirror') {
  11198.             if ($ret !== null) {
  11199.                 $reg = &$this->getRegistry($layer);
  11200.                 if (is_object($reg)) {
  11201.                     $chan = &$reg->getChannel($channel);
  11202.                     if (PEAR::isError($chan)) {
  11203.                         return $channel;
  11204.                     }
  11205.                     if (!$chan->getMirror($ret) && $chan->getName() != $ret) {
  11206.                         return $channel; // mirror does not exist
  11207.                     }
  11208.                 }
  11209.                 return $ret;
  11210.             }
  11211.             if ($channel != $this->getDefaultChannel($layer)) {
  11212.                 return $channel; // we must use the channel name as the preferred mirror
  11213.                                  // if the user has not chosen an alternate
  11214.             } else {
  11215.                 return $this->getDefaultChannel($layer);
  11216.             }
  11217.         }
  11218.         return $ret;
  11219.     }
  11220.  
  11221.  
  11222.     // }}}
  11223.     // {{{ set(key, value, [layer])
  11224.  
  11225.     /**
  11226.      * Set a config value in a specific layer (defaults to 'user').
  11227.      * Enforces the types defined in the configuration_info array.  An
  11228.      * integer config variable will be cast to int, and a set config
  11229.      * variable will be validated against its legal values.
  11230.      *
  11231.      * @param string config key
  11232.      * @param string config value
  11233.      * @param string (optional) config layer
  11234.      * @param string channel to set this value for, or null for global value
  11235.      * @return bool TRUE on success, FALSE on failure
  11236.      */
  11237.     function set($key, $value, $layer = 'user', $channel = false)
  11238.     {
  11239.         if ($key == '__channels') {
  11240.             return false;
  11241.         }
  11242.         if (!isset($this->configuration[$layer])) {
  11243.             return false;
  11244.         }
  11245.         if ($key == 'default_channel') {
  11246.             // can only set this value globally
  11247.             $channel = 'pear.php.net';
  11248.             if ($value != 'pear.php.net') {
  11249.                 $this->_lazyChannelSetup($layer);
  11250.             }
  11251.         }
  11252.         if ($key == 'preferred_mirror') {
  11253.             if ($channel == '__uri') {
  11254.                 return false; // can't set the __uri pseudo-channel's mirror
  11255.             }
  11256.             $reg = &$this->getRegistry($layer);
  11257.             if (is_object($reg)) {
  11258.                 $chan = &$reg->getChannel($channel ? $channel : 'pear.php.net');
  11259.                 if (PEAR::isError($chan)) {
  11260.                     return false;
  11261.                 }
  11262.                 if (!$chan->getMirror($value) && $chan->getName() != $value) {
  11263.                     return false; // mirror does not exist
  11264.                 }
  11265.             }
  11266.         }
  11267.         if (!isset($this->configuration_info[$key])) {
  11268.             return false;
  11269.         }
  11270.         extract($this->configuration_info[$key]);
  11271.         switch ($type) {
  11272.             case 'integer':
  11273.                 $value = (int)$value;
  11274.                 break;
  11275.             case 'set': {
  11276.                 // If a valid_set is specified, require the value to
  11277.                 // be in the set.  If there is no valid_set, accept
  11278.                 // any value.
  11279.                 if ($valid_set) {
  11280.                     reset($valid_set);
  11281.                     if ((key($valid_set) === 0 && !in_array($value, $valid_set)) ||
  11282.                         (key($valid_set) !== 0 && empty($valid_set[$value])))
  11283.                     {
  11284.                         return false;
  11285.                     }
  11286.                 }
  11287.                 break;
  11288.             }
  11289.         }
  11290.         if (!$channel) {
  11291.             $channel = $this->get('default_channel', null, 'pear.php.net');
  11292.         }
  11293.         if (!in_array($channel, $this->_channels)) {
  11294.             $this->_lazyChannelSetup($layer);
  11295.             $reg = &$this->getRegistry($layer);
  11296.             if ($reg) {
  11297.                 $channel = $reg->channelName($channel);
  11298.             }
  11299.             if (!in_array($channel, $this->_channels)) {
  11300.                 return false;
  11301.             }
  11302.         }
  11303.         if ($channel != 'pear.php.net') {
  11304.             if (in_array($key, $this->_channelConfigInfo)) {
  11305.                 $this->configuration[$layer]['__channels'][$channel][$key] = $value;
  11306.                 return true;
  11307.             } else {
  11308.                 return false;
  11309.             }
  11310.         } else {
  11311.             if ($key == 'default_channel') {
  11312.                 if (!isset($reg)) {
  11313.                     $reg = &$this->getRegistry($layer);
  11314.                     if (!$reg) {
  11315.                         $reg = &$this->getRegistry();
  11316.                     }
  11317.                 }
  11318.                 if ($reg) {
  11319.                     $value = $reg->channelName($value);
  11320.                 }
  11321.                 if (!$value) {
  11322.                     return false;
  11323.                 }
  11324.             }
  11325.         }
  11326.         $this->configuration[$layer][$key] = $value;
  11327.         if ($key == 'php_dir' && !$this->_noRegistry) {
  11328.             if (!isset($this->_registry[$layer]) ||
  11329.                   $value != $this->_registry[$layer]->install_dir) {
  11330.                 $this->_registry[$layer] = &new PEAR_Registry($value);
  11331.                 $this->_regInitialized[$layer] = false;
  11332.                 $this->_registry[$layer]->setConfig($this);
  11333.             }
  11334.         }
  11335.         return true;
  11336.     }
  11337.  
  11338.     // }}}
  11339.     function _lazyChannelSetup($uselayer = false)
  11340.     {
  11341.         if ($this->_noRegistry) {
  11342.             return;
  11343.         }
  11344.         $merge = false;
  11345.         foreach ($this->_registry as $layer => $p) {
  11346.             if ($uselayer && $uselayer != $layer) {
  11347.                 continue;
  11348.             }
  11349.             if (!$this->_regInitialized[$layer]) {
  11350.                 if ($layer == 'default' && isset($this->_registry['user']) ||
  11351.                       isset($this->_registry['system'])) {
  11352.                     // only use the default registry if there are no alternatives
  11353.                     continue;
  11354.                 }
  11355.                 if (!is_object($this->_registry[$layer])) {
  11356.                     if ($phpdir = $this->get('php_dir', $layer, 'pear.php.net')) {
  11357.                         $this->_registry[$layer] = &new PEAR_Registry($phpdir);
  11358.                         $this->_registry[$layer]->setConfig($this);
  11359.                         $this->_regInitialized[$layer] = false;
  11360.                     } else {
  11361.                         unset($this->_registry[$layer]);
  11362.                         return;
  11363.                     }
  11364.                 }
  11365.                 $this->setChannels($this->_registry[$layer]->listChannels(), $merge);
  11366.                 $this->_regInitialized[$layer] = true;
  11367.                 $merge = true;
  11368.             }
  11369.         }
  11370.     }
  11371.     // {{{ setChannels()
  11372.     
  11373.     /**
  11374.      * Set the list of channels.
  11375.      *
  11376.      * This should be set via a call to {@link PEAR_Registry::listChannels()}
  11377.      * @param array
  11378.      * @param bool
  11379.      * @return bool success of operation
  11380.      */
  11381.     function setChannels($channels, $merge = false)
  11382.     {
  11383.         if (!is_array($channels)) {
  11384.             return false;
  11385.         }
  11386.         if ($merge) {
  11387.             $this->_channels = array_merge($this->_channels, $channels);
  11388.         } else {
  11389.             $this->_channels = $channels;
  11390.         }
  11391.         foreach ($channels as $channel) {
  11392.             $channel = strtolower($channel);
  11393.             if ($channel == 'pear.php.net') {
  11394.                 continue;
  11395.             }
  11396.             foreach ($this->layers as $layer) {
  11397.                 if (!isset($this->configuration[$layer]['__channels'])) {
  11398.                     $this->configuration[$layer]['__channels'] = array();
  11399.                 }
  11400.                 if (!isset($this->configuration[$layer]['__channels'][$channel])
  11401.                       || !is_array($this->configuration[$layer]['__channels'][$channel])) {
  11402.                     $this->configuration[$layer]['__channels'][$channel] = array();
  11403.                 }
  11404.             }
  11405.         }
  11406.         return true;
  11407.     }
  11408.  
  11409.     // }}}
  11410.     // {{{ getType(key)
  11411.  
  11412.     /**
  11413.      * Get the type of a config value.
  11414.      *
  11415.      * @param string  config key
  11416.      *
  11417.      * @return string type, one of "string", "integer", "file",
  11418.      * "directory", "set" or "password".
  11419.      *
  11420.      * @access public
  11421.      *
  11422.      */
  11423.     function getType($key)
  11424.     {
  11425.         if (isset($this->configuration_info[$key])) {
  11426.             return $this->configuration_info[$key]['type'];
  11427.         }
  11428.         return false;
  11429.     }
  11430.  
  11431.     // }}}
  11432.     // {{{ getDocs(key)
  11433.  
  11434.     /**
  11435.      * Get the documentation for a config value.
  11436.      *
  11437.      * @param string  config key
  11438.      *
  11439.      * @return string documentation string
  11440.      *
  11441.      * @access public
  11442.      *
  11443.      */
  11444.     function getDocs($key)
  11445.     {
  11446.         if (isset($this->configuration_info[$key])) {
  11447.             return $this->configuration_info[$key]['doc'];
  11448.         }
  11449.         return false;
  11450.     }
  11451.        // }}}
  11452.     // {{{ getPrompt(key)
  11453.  
  11454.     /**
  11455.      * Get the short documentation for a config value.
  11456.      *
  11457.      * @param string  config key
  11458.      *
  11459.      * @return string short documentation string
  11460.      *
  11461.      * @access public
  11462.      *
  11463.      */
  11464.     function getPrompt($key)
  11465.     {
  11466.         if (isset($this->configuration_info[$key])) {
  11467.             return $this->configuration_info[$key]['prompt'];
  11468.         }
  11469.         return false;
  11470.     }
  11471.     // }}}
  11472.     // {{{ getGroup(key)
  11473.  
  11474.     /**
  11475.      * Get the parameter group for a config key.
  11476.      *
  11477.      * @param string  config key
  11478.      *
  11479.      * @return string parameter group
  11480.      *
  11481.      * @access public
  11482.      *
  11483.      */
  11484.     function getGroup($key)
  11485.     {
  11486.         if (isset($this->configuration_info[$key])) {
  11487.             return $this->configuration_info[$key]['group'];
  11488.         }
  11489.         return false;
  11490.     }
  11491.  
  11492.     // }}}
  11493.     // {{{ getGroups()
  11494.  
  11495.     /**
  11496.      * Get the list of parameter groups.
  11497.      *
  11498.      * @return array list of parameter groups
  11499.      *
  11500.      * @access public
  11501.      *
  11502.      */
  11503.     function getGroups()
  11504.     {
  11505.         $tmp = array();
  11506.         foreach ($this->configuration_info as $key => $info) {
  11507.             $tmp[$info['group']] = 1;
  11508.         }
  11509.         return array_keys($tmp);
  11510.     }
  11511.  
  11512.     // }}}
  11513.     // {{{ getGroupKeys()
  11514.  
  11515.     /**
  11516.      * Get the list of the parameters in a group.
  11517.      *
  11518.      * @param string $group parameter group
  11519.      *
  11520.      * @return array list of parameters in $group
  11521.      *
  11522.      * @access public
  11523.      *
  11524.      */
  11525.     function getGroupKeys($group)
  11526.     {
  11527.         $keys = array();
  11528.         foreach ($this->configuration_info as $key => $info) {
  11529.             if ($info['group'] == $group) {
  11530.                 $keys[] = $key;
  11531.             }
  11532.         }
  11533.         return $keys;
  11534.     }
  11535.  
  11536.     // }}}
  11537.     // {{{ getSetValues(key)
  11538.  
  11539.     /**
  11540.      * Get the list of allowed set values for a config value.  Returns
  11541.      * NULL for config values that are not sets.
  11542.      *
  11543.      * @param string  config key
  11544.      *
  11545.      * @return array enumerated array of set values, or NULL if the
  11546.      *               config key is unknown or not a set
  11547.      *
  11548.      * @access public
  11549.      *
  11550.      */
  11551.     function getSetValues($key)
  11552.     {
  11553.         if (isset($this->configuration_info[$key]) &&
  11554.             isset($this->configuration_info[$key]['type']) &&
  11555.             $this->configuration_info[$key]['type'] == 'set')
  11556.         {
  11557.             $valid_set = $this->configuration_info[$key]['valid_set'];
  11558.             reset($valid_set);
  11559.             if (key($valid_set) === 0) {
  11560.                 return $valid_set;
  11561.             }
  11562.             return array_keys($valid_set);
  11563.         }
  11564.         return null;
  11565.     }
  11566.  
  11567.     // }}}
  11568.     // {{{ getKeys()
  11569.  
  11570.     /**
  11571.      * Get all the current config keys.
  11572.      *
  11573.      * @return array simple array of config keys
  11574.      *
  11575.      * @access public
  11576.      */
  11577.     function getKeys()
  11578.     {
  11579.         $keys = array();
  11580.         foreach ($this->layers as $layer) {
  11581.             $test = $this->configuration[$layer];
  11582.             if (isset($test['__channels'])) {
  11583.                 foreach ($test['__channels'] as $channel => $configs) {
  11584.                     $keys = array_merge($keys, $configs);
  11585.                 }
  11586.             }
  11587.             unset($test['__channels']);
  11588.             $keys = array_merge($keys, $test);
  11589.         }
  11590.         return array_keys($keys);
  11591.     }
  11592.  
  11593.     // }}}
  11594.     // {{{ remove(key, [layer])
  11595.  
  11596.     /**
  11597.      * Remove the a config key from a specific config layer.
  11598.      *
  11599.      * @param string config key
  11600.      *
  11601.      * @param string (optional) config layer
  11602.      *
  11603.      * @return bool TRUE on success, FALSE on failure
  11604.      *
  11605.      * @access public
  11606.      */
  11607.     function remove($key, $layer = 'user')
  11608.     {
  11609.         $channel = $this->getDefaultChannel();
  11610.         if ($channel !== 'pear.php.net') {
  11611.             if (isset($this->configuration[$layer]['__channels'][$channel][$key])) {
  11612.                 unset($this->configuration[$layer]['__channels'][$channel][$key]);
  11613.                 return true;
  11614.             }
  11615.         }
  11616.         if (isset($this->configuration[$layer][$key])) {
  11617.             unset($this->configuration[$layer][$key]);
  11618.             return true;
  11619.         }
  11620.         return false;
  11621.     }
  11622.  
  11623.     // }}}
  11624.     // {{{ removeLayer(layer)
  11625.  
  11626.     /**
  11627.      * Temporarily remove an entire config layer.  USE WITH CARE!
  11628.      *
  11629.      * @param string config key
  11630.      *
  11631.      * @param string (optional) config layer
  11632.      *
  11633.      * @return bool TRUE on success, FALSE on failure
  11634.      *
  11635.      * @access public
  11636.      */
  11637.     function removeLayer($layer)
  11638.     {
  11639.         if (isset($this->configuration[$layer])) {
  11640.             $this->configuration[$layer] = array();
  11641.             return true;
  11642.         }
  11643.         return false;
  11644.     }
  11645.  
  11646.     // }}}
  11647.     // {{{ store([layer])
  11648.  
  11649.     /**
  11650.      * Stores configuration data in a layer.
  11651.      *
  11652.      * @param string config layer to store
  11653.      *
  11654.      * @return bool TRUE on success, or PEAR error on failure
  11655.      *
  11656.      * @access public
  11657.      */
  11658.     function store($layer = 'user', $data = null)
  11659.     {
  11660.         return $this->writeConfigFile(null, $layer, $data);
  11661.     }
  11662.  
  11663.     // }}}
  11664.     // {{{ toDefault(key)
  11665.  
  11666.     /**
  11667.      * Unset the user-defined value of a config key, reverting the
  11668.      * value to the system-defined one.
  11669.      *
  11670.      * @param string config key
  11671.      *
  11672.      * @return bool TRUE on success, FALSE on failure
  11673.      *
  11674.      * @access public
  11675.      */
  11676.     function toDefault($key)
  11677.     {
  11678.         trigger_error("PEAR_Config::toDefault() deprecated, use PEAR_Config::remove() instead", E_USER_NOTICE);
  11679.         return $this->remove($key, 'user');
  11680.     }
  11681.  
  11682.     // }}}
  11683.     // {{{ definedBy(key)
  11684.  
  11685.     /**
  11686.      * Tells what config layer that gets to define a key.
  11687.      *
  11688.      * @param string config key
  11689.      * @param boolean return the defining channel
  11690.      *
  11691.      * @return string|array the config layer, or an empty string if not found.
  11692.      *
  11693.      *         if $returnchannel, the return is an array array('layer' => layername,
  11694.      *         'channel' => channelname), or an empty string if not found
  11695.      *
  11696.      * @access public
  11697.      */
  11698.     function definedBy($key, $returnchannel = false)
  11699.     {
  11700.         foreach ($this->layers as $layer) {
  11701.             $channel = $this->getDefaultChannel();
  11702.             if ($channel !== 'pear.php.net') {
  11703.                 if (isset($this->configuration[$layer]['__channels'][$channel][$key])) {
  11704.                     if ($returnchannel) {
  11705.                         return array('layer' => $layer, 'channel' => $channel);
  11706.                     }
  11707.                     return $layer;
  11708.                 }
  11709.             }
  11710.             if (isset($this->configuration[$layer][$key])) {
  11711.                 if ($returnchannel) {
  11712.                     return array('layer' => $layer, 'channel' => 'pear.php.net');
  11713.                 }
  11714.                 return $layer;
  11715.             }
  11716.         }
  11717.         return '';
  11718.     }
  11719.  
  11720.     // }}}
  11721.     // {{{ isDefaulted(key)
  11722.  
  11723.     /**
  11724.      * Tells whether a config value has a system-defined value.
  11725.      *
  11726.      * @param string   config key
  11727.      *
  11728.      * @return bool
  11729.      *
  11730.      * @access public
  11731.      *
  11732.      * @deprecated
  11733.      */
  11734.     function isDefaulted($key)
  11735.     {
  11736.         trigger_error("PEAR_Config::isDefaulted() deprecated, use PEAR_Config::definedBy() instead", E_USER_NOTICE);
  11737.         return $this->definedBy($key) == 'system';
  11738.     }
  11739.  
  11740.     // }}}
  11741.     // {{{ isDefined(key)
  11742.  
  11743.     /**
  11744.      * Tells whether a given key exists as a config value.
  11745.      *
  11746.      * @param string config key
  11747.      *
  11748.      * @return bool whether <config key> exists in this object
  11749.      *
  11750.      * @access public
  11751.      */
  11752.     function isDefined($key)
  11753.     {
  11754.         foreach ($this->layers as $layer) {
  11755.             if (isset($this->configuration[$layer][$key])) {
  11756.                 return true;
  11757.             }
  11758.         }
  11759.         return false;
  11760.     }
  11761.  
  11762.     // }}}
  11763.     // {{{ isDefinedLayer(key)
  11764.  
  11765.     /**
  11766.      * Tells whether a given config layer exists.
  11767.      *
  11768.      * @param string config layer
  11769.      *
  11770.      * @return bool whether <config layer> exists in this object
  11771.      *
  11772.      * @access public
  11773.      */
  11774.     function isDefinedLayer($layer)
  11775.     {
  11776.         return isset($this->configuration[$layer]);
  11777.     }
  11778.  
  11779.     // }}}
  11780.     // {{{ getLayers()
  11781.  
  11782.     /**
  11783.      * Returns the layers defined (except the 'default' one)
  11784.      *
  11785.      * @return array of the defined layers
  11786.      */
  11787.     function getLayers()
  11788.     {
  11789.         $cf = $this->configuration;
  11790.         unset($cf['default']);
  11791.         return array_keys($cf);
  11792.     }
  11793.  
  11794.     // }}}
  11795.     // {{{ apiVersion()
  11796.     function apiVersion()
  11797.     {
  11798.         return '1.1';
  11799.     }
  11800.     // }}}
  11801.  
  11802.     /**
  11803.      * @return PEAR_Registry
  11804.      */
  11805.     function &getRegistry($use = null)
  11806.     {
  11807.         if ($use === null) {
  11808.             $layer = 'user';
  11809.         } else {
  11810.             $layer = $use;
  11811.         }
  11812.         if (isset($this->_registry[$layer])) {
  11813.             return $this->_registry[$layer];
  11814.         } elseif ($use === null && isset($this->_registry['system'])) {
  11815.             return $this->_registry['system'];
  11816.         } elseif ($use === null && isset($this->_registry['default'])) {
  11817.             return $this->_registry['default'];
  11818.         } elseif ($use) {
  11819.             $a = false;
  11820.             return $a;
  11821.         } else {
  11822.             // only go here if null was passed in
  11823.             echo "CRITICAL ERROR: Registry could not be initialized from any value";
  11824.             exit(1);
  11825.         }
  11826.     }
  11827.     /**
  11828.      * This is to allow customization like the use of installroot
  11829.      * @param PEAR_Registry
  11830.      * @return bool
  11831.      */
  11832.     function setRegistry(&$reg, $layer = 'user')
  11833.     {
  11834.         if ($this->_noRegistry) {
  11835.             return false;
  11836.         }
  11837.         if (!in_array($layer, array('user', 'system'))) {
  11838.             return false;
  11839.         }
  11840.         $this->_registry[$layer] = &$reg;
  11841.         if (is_object($reg)) {
  11842.             $this->_registry[$layer]->setConfig($this);
  11843.         }
  11844.         return true;
  11845.     }
  11846.  
  11847.     function noRegistry()
  11848.     {
  11849.         $this->_noRegistry = true;
  11850.     }
  11851.  
  11852.     /**
  11853.      * @return PEAR_Remote
  11854.      */
  11855.     function &getRemote()
  11856.     {
  11857.         $remote = &new PEAR_Remote($this);
  11858.         return $remote;
  11859.     }
  11860.  
  11861.     /**
  11862.      * @return PEAR_REST
  11863.      */
  11864.     function &getREST($version, $options = array())
  11865.     {
  11866.         $version = str_replace('.', '', $version);
  11867.         if (!class_exists($class = 'PEAR_REST_' . $version)) {
  11868.             require_once 'phar://go-pear.phar/' . 'PEAR/REST/' . $version . '.php';
  11869.         }
  11870.         $remote = &new $class($this, $options);
  11871.         return $remote;
  11872.     }
  11873.  
  11874.     /**
  11875.      * The ftp server is set in {@link readFTPConfigFile()}.  It exists only if a
  11876.      * remote configuration file has been specified
  11877.      * @return PEAR_FTP|false
  11878.      */
  11879.     function &getFTP()
  11880.     {
  11881.         if (isset($this->_ftp)) {
  11882.             return $this->_ftp;
  11883.         } else {
  11884.             $a = false;
  11885.             return $a;
  11886.         }
  11887.     }
  11888.  
  11889.     // {{{ _prependPath($path, $prepend)
  11890.  
  11891.     function _prependPath($path, $prepend)
  11892.     {
  11893.         if (strlen($prepend) > 0) {
  11894.             if (OS_WINDOWS && preg_match('/^[a-z]:/i', $path)) {
  11895.                 if (preg_match('/^[a-z]:/i', $prepend)) {
  11896.                     $prepend = substr($prepend, 2);
  11897.                 } elseif ($prepend{0} != '\\') {
  11898.                     $prepend = "\\$prepend";
  11899.                 }
  11900.                 $path = substr($path, 0, 2) . $prepend . substr($path, 2);
  11901.             } else {
  11902.                 $path = $prepend . $path;
  11903.             }
  11904.         }
  11905.         return $path;
  11906.     }
  11907.     // }}}
  11908.  
  11909.     /**
  11910.      * @param string|false installation directory to prepend to all _dir variables, or false to
  11911.      *                     disable
  11912.      */
  11913.     function setInstallRoot($root)
  11914.     {
  11915.         if (substr($root, -1) == DIRECTORY_SEPARATOR) {
  11916.             $root = substr($root, 0, -1);
  11917.         }
  11918.         $old = $this->_installRoot;
  11919.         $this->_installRoot = $root;
  11920.         if (($old != $root) && !$this->_noRegistry) {
  11921.             foreach (array_keys($this->_registry) as $layer) {
  11922.                 if ($layer == 'ftp' || !isset($this->_registry[$layer])) {
  11923.                     continue;
  11924.                 }
  11925.                 $this->_registry[$layer] =
  11926.                     &new PEAR_Registry($this->get('php_dir', $layer, 'pear.php.net'));
  11927.                 $this->_registry[$layer]->setConfig($this);
  11928.                 $this->_regInitialized[$layer] = false;
  11929.             }
  11930.         }
  11931.     }
  11932. }
  11933.  
  11934. ?>
  11935. <?php
  11936. /**
  11937.  * PEAR_Dependency2, advanced dependency validation
  11938.  *
  11939.  * PHP versions 4 and 5
  11940.  *
  11941.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  11942.  * that is available through the world-wide-web at the following URI:
  11943.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  11944.  * the PHP License and are unable to obtain it through the web, please
  11945.  * send a note to license@php.net so we can mail you a copy immediately.
  11946.  *
  11947.  * @category   pear
  11948.  * @package    PEAR
  11949.  * @author     Greg Beaver <cellog@php.net>
  11950.  * @copyright  1997-2008 The PHP Group
  11951.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  11952.  * @version    CVS: $Id: Dependency2.php,v 1.56 2008/01/03 20:26:35 cellog Exp $
  11953.  * @link       http://pear.php.net/package/PEAR
  11954.  * @since      File available since Release 1.4.0a1
  11955.  */
  11956.  
  11957. /**
  11958.  * Required for the PEAR_VALIDATE_* constants
  11959.  */
  11960. require_once 'phar://go-pear.phar/' . 'PEAR/Validate.php';
  11961.  
  11962. /**
  11963.  * Dependency check for PEAR packages
  11964.  *
  11965.  * This class handles both version 1.0 and 2.0 dependencies
  11966.  * WARNING: *any* changes to this class must be duplicated in the
  11967.  * test_PEAR_Dependency2 class found in tests/PEAR_Dependency2/setup.php.inc,
  11968.  * or unit tests will not actually validate the changes
  11969.  * @category   pear
  11970.  * @package    PEAR
  11971.  * @author     Greg Beaver <cellog@php.net>
  11972.  * @copyright  1997-2008 The PHP Group
  11973.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  11974.  * @version    Release: 1.7.1
  11975.  * @link       http://pear.php.net/package/PEAR
  11976.  * @since      Class available since Release 1.4.0a1
  11977.  */
  11978. class PEAR_Dependency2
  11979. {
  11980.     /**
  11981.      * One of the PEAR_VALIDATE_* states
  11982.      * @see PEAR_VALIDATE_NORMAL
  11983.      * @var integer
  11984.      */
  11985.     var $_state;
  11986.     /**
  11987.      * Command-line options to install/upgrade/uninstall commands
  11988.      * @param array
  11989.      */
  11990.     var $_options;
  11991.     /**
  11992.      * @var OS_Guess
  11993.      */
  11994.     var $_os;
  11995.     /**
  11996.      * @var PEAR_Registry
  11997.      */
  11998.     var $_registry;
  11999.     /**
  12000.      * @var PEAR_Config
  12001.      */
  12002.     var $_config;
  12003.     /**
  12004.      * @var PEAR_DependencyDB
  12005.      */
  12006.     var $_dependencydb;
  12007.     /**
  12008.      * Output of PEAR_Registry::parsedPackageName()
  12009.      * @var array
  12010.      */
  12011.     var $_currentPackage;
  12012.     /**
  12013.      * @param PEAR_Config
  12014.      * @param array installation options
  12015.      * @param array format of PEAR_Registry::parsedPackageName()
  12016.      * @param int installation state (one of PEAR_VALIDATE_*)
  12017.      */
  12018.     function PEAR_Dependency2(&$config, $installoptions, $package,
  12019.                               $state = PEAR_VALIDATE_INSTALLING)
  12020.     {
  12021.         $this->_config = &$config;
  12022.         if (!class_exists('PEAR_DependencyDB')) {
  12023.             require_once 'phar://go-pear.phar/' . 'PEAR/DependencyDB.php';
  12024.         }
  12025.         if (isset($installoptions['packagingroot'])) {
  12026.             // make sure depdb is in the right location
  12027.             $config->setInstallRoot($installoptions['packagingroot']);
  12028.         }
  12029.         $this->_registry = &$config->getRegistry();
  12030.         $this->_dependencydb = &PEAR_DependencyDB::singleton($config);
  12031.         if (isset($installoptions['packagingroot'])) {
  12032.             $config->setInstallRoot(false);
  12033.         }
  12034.         $this->_options = $installoptions;
  12035.         $this->_state = $state;
  12036.         if (!class_exists('OS_Guess')) {
  12037.             require_once 'phar://go-pear.phar/' . 'OS/Guess.php';
  12038.         }
  12039.         $this->_os = new OS_Guess;
  12040.         $this->_currentPackage = $package;
  12041.     }
  12042.  
  12043.     function _getExtraString($dep)
  12044.     {
  12045.         $extra = ' (';
  12046.         if (isset($dep['uri'])) {
  12047.             return '';
  12048.         }
  12049.         if (isset($dep['recommended'])) {
  12050.             $extra .= 'recommended version ' . $dep['recommended'];
  12051.         } else {
  12052.             if (isset($dep['min'])) {
  12053.                 $extra .= 'version >= ' . $dep['min'];
  12054.             }
  12055.             if (isset($dep['max'])) {
  12056.                 if ($extra != ' (') {
  12057.                     $extra .= ', ';
  12058.                 }
  12059.                 $extra .= 'version <= ' . $dep['max'];
  12060.             }
  12061.             if (isset($dep['exclude'])) {
  12062.                 if (!is_array($dep['exclude'])) {
  12063.                     $dep['exclude'] = array($dep['exclude']);
  12064.                 }
  12065.                 if ($extra != ' (') {
  12066.                     $extra .= ', ';
  12067.                 }
  12068.                 $extra .= 'excluded versions: ';
  12069.                 foreach ($dep['exclude'] as $i => $exclude) {
  12070.                     if ($i) {
  12071.                         $extra .= ', ';
  12072.                     }
  12073.                     $extra .= $exclude;
  12074.                 }
  12075.             }
  12076.         }
  12077.         $extra .= ')';
  12078.         if ($extra == ' ()') {
  12079.             $extra = '';
  12080.         }
  12081.         return $extra;
  12082.     }
  12083.  
  12084.     /**
  12085.      * This makes unit-testing a heck of a lot easier
  12086.      */
  12087.     function getPHP_OS()
  12088.     {
  12089.         return PHP_OS;
  12090.     }
  12091.  
  12092.     /**
  12093.      * This makes unit-testing a heck of a lot easier
  12094.      */
  12095.     function getsysname()
  12096.     {
  12097.         return $this->_os->getSysname();
  12098.     }
  12099.  
  12100.     /**
  12101.      * Specify a dependency on an OS.  Use arch for detailed os/processor information
  12102.      *
  12103.      * There are two generic OS dependencies that will be the most common, unix and windows.
  12104.      * Other options are linux, freebsd, darwin (OS X), sunos, irix, hpux, aix
  12105.      */
  12106.     function validateOsDependency($dep)
  12107.     {
  12108.         if ($this->_state != PEAR_VALIDATE_INSTALLING &&
  12109.               $this->_state != PEAR_VALIDATE_DOWNLOADING) {
  12110.             return true;
  12111.         }
  12112.         if (isset($dep['conflicts'])) {
  12113.             $not = true;
  12114.         } else {
  12115.             $not = false;
  12116.         }
  12117.         if ($dep['name'] == '*') {
  12118.             return true;
  12119.         }
  12120.         switch (strtolower($dep['name'])) {
  12121.             case 'windows' :
  12122.                 if ($not) {
  12123.                     if (strtolower(substr($this->getPHP_OS(), 0, 3)) == 'win') {
  12124.                         if (!isset($this->_options['nodeps']) &&
  12125.                               !isset($this->_options['force'])) {
  12126.                             return $this->raiseError("Cannot install %s on Windows");
  12127.                         } else {
  12128.                             return $this->warning("warning: Cannot install %s on Windows");
  12129.                         }
  12130.                     }
  12131.                 } else {
  12132.                     if (strtolower(substr($this->getPHP_OS(), 0, 3)) != 'win') {
  12133.                         if (!isset($this->_options['nodeps']) &&
  12134.                               !isset($this->_options['force'])) {
  12135.                             return $this->raiseError("Can only install %s on Windows");
  12136.                         } else {
  12137.                             return $this->warning("warning: Can only install %s on Windows");
  12138.                         }
  12139.                     }
  12140.                 }
  12141.             break;
  12142.             case 'unix' :
  12143.                 $unices = array('linux', 'freebsd', 'darwin', 'sunos', 'irix', 'hpux', 'aix');
  12144.                 if ($not) {
  12145.                     if (in_array($this->getSysname(), $unices)) {
  12146.                         if (!isset($this->_options['nodeps']) &&
  12147.                               !isset($this->_options['force'])) {
  12148.                             return $this->raiseError("Cannot install %s on any Unix system");
  12149.                         } else {
  12150.                             return $this->warning(
  12151.                                 "warning: Cannot install %s on any Unix system");
  12152.                         }
  12153.                     }
  12154.                 } else {
  12155.                     if (!in_array($this->getSysname(), $unices)) {
  12156.                         if (!isset($this->_options['nodeps']) &&
  12157.                               !isset($this->_options['force'])) {
  12158.                             return $this->raiseError("Can only install %s on a Unix system");
  12159.                         } else {
  12160.                             return $this->warning(
  12161.                                 "warning: Can only install %s on a Unix system");
  12162.                         }
  12163.                     }
  12164.                 }
  12165.             break;
  12166.             default :
  12167.                 if ($not) {
  12168.                     if (strtolower($dep['name']) == strtolower($this->getSysname())) {
  12169.                         if (!isset($this->_options['nodeps']) &&
  12170.                               !isset($this->_options['force'])) {
  12171.                             return $this->raiseError('Cannot install %s on ' . $dep['name'] .
  12172.                                 ' operating system');
  12173.                         } else {
  12174.                             return $this->warning('warning: Cannot install %s on ' .
  12175.                                 $dep['name'] . ' operating system');
  12176.                         }
  12177.                     }
  12178.                 } else {
  12179.                     if (strtolower($dep['name']) != strtolower($this->getSysname())) {
  12180.                         if (!isset($this->_options['nodeps']) &&
  12181.                               !isset($this->_options['force'])) {
  12182.                             return $this->raiseError('Cannot install %s on ' .
  12183.                                 $this->getSysname() .
  12184.                                 ' operating system, can only install on ' . $dep['name']);
  12185.                         } else {
  12186.                             return $this->warning('warning: Cannot install %s on ' .
  12187.                                 $this->getSysname() .
  12188.                                 ' operating system, can only install on ' . $dep['name']);
  12189.                         }
  12190.                     }
  12191.                 }
  12192.         }
  12193.         return true;
  12194.     }
  12195.  
  12196.     /**
  12197.      * This makes unit-testing a heck of a lot easier
  12198.      */
  12199.     function matchSignature($pattern)
  12200.     {
  12201.         return $this->_os->matchSignature($pattern);
  12202.     }
  12203.  
  12204.     /**
  12205.      * Specify a complex dependency on an OS/processor/kernel version,
  12206.      * Use OS for simple operating system dependency.
  12207.      *
  12208.      * This is the only dependency that accepts an eregable pattern.  The pattern
  12209.      * will be matched against the php_uname() output parsed by OS_Guess
  12210.      */
  12211.     function validateArchDependency($dep)
  12212.     {
  12213.         if ($this->_state != PEAR_VALIDATE_INSTALLING) {
  12214.             return true;
  12215.         }
  12216.         if (isset($dep['conflicts'])) {
  12217.             $not = true;
  12218.         } else {
  12219.             $not = false;
  12220.         }
  12221.         if (!$this->matchSignature($dep['pattern'])) {
  12222.             if (!$not) {
  12223.                 if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  12224.                     return $this->raiseError('%s Architecture dependency failed, does not ' .
  12225.                         'match "' . $dep['pattern'] . '"');
  12226.                 } else {
  12227.                     return $this->warning('warning: %s Architecture dependency failed, does ' .
  12228.                         'not match "' . $dep['pattern'] . '"');
  12229.                 }
  12230.             }
  12231.             return true;
  12232.         } else {
  12233.             if ($not) {
  12234.                 if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  12235.                     return $this->raiseError('%s Architecture dependency failed, required "' .
  12236.                         $dep['pattern'] . '"');
  12237.                 } else {
  12238.                     return $this->warning('warning: %s Architecture dependency failed, ' .
  12239.                         'required "' . $dep['pattern'] . '"');
  12240.                 }
  12241.             }
  12242.             return true;
  12243.         }
  12244.     }
  12245.  
  12246.     /**
  12247.      * This makes unit-testing a heck of a lot easier
  12248.      */
  12249.     function extension_loaded($name)
  12250.     {
  12251.         return extension_loaded($name);
  12252.     }
  12253.  
  12254.     /**
  12255.      * This makes unit-testing a heck of a lot easier
  12256.      */
  12257.     function phpversion($name = null)
  12258.     {
  12259.         if ($name !== null) {
  12260.             return phpversion($name);
  12261.         } else {
  12262.             return phpversion();
  12263.         }
  12264.     }
  12265.  
  12266.     function validateExtensionDependency($dep, $required = true)
  12267.     {
  12268.         if ($this->_state != PEAR_VALIDATE_INSTALLING &&
  12269.               $this->_state != PEAR_VALIDATE_DOWNLOADING) {
  12270.             return true;
  12271.         }
  12272.         $loaded = $this->extension_loaded($dep['name']);
  12273.         $extra = $this->_getExtraString($dep);
  12274.         if (isset($dep['exclude'])) {
  12275.             if (!is_array($dep['exclude'])) {
  12276.                 $dep['exclude'] = array($dep['exclude']);
  12277.             }
  12278.         }
  12279.         if (!isset($dep['min']) && !isset($dep['max']) &&
  12280.               !isset($dep['recommended']) && !isset($dep['exclude'])) {
  12281.             if ($loaded) {
  12282.                 if (isset($dep['conflicts'])) {
  12283.                     if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  12284.                         return $this->raiseError('%s conflicts with PHP extension "' .
  12285.                             $dep['name'] . '"' . $extra);
  12286.                     } else {
  12287.                         return $this->warning('warning: %s conflicts with PHP extension "' .
  12288.                             $dep['name'] . '"' . $extra);
  12289.                     }
  12290.                 }
  12291.                 return true;
  12292.             } else {
  12293.                 if (isset($dep['conflicts'])) {
  12294.                     return true;
  12295.                 }
  12296.                 if ($required) {
  12297.                     if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  12298.                         return $this->raiseError('%s requires PHP extension "' .
  12299.                             $dep['name'] . '"' . $extra);
  12300.                     } else {
  12301.                         return $this->warning('warning: %s requires PHP extension "' .
  12302.                             $dep['name'] . '"' . $extra);
  12303.                     }
  12304.                 } else {
  12305.                     return $this->warning('%s can optionally use PHP extension "' .
  12306.                         $dep['name'] . '"' . $extra);
  12307.                 }
  12308.             }
  12309.         }
  12310.         if (!$loaded) {
  12311.             if (isset($dep['conflicts'])) {
  12312.                 return true;
  12313.             }
  12314.             if (!$required) {
  12315.                 return $this->warning('%s can optionally use PHP extension "' .
  12316.                     $dep['name'] . '"' . $extra);
  12317.             } else {
  12318.                 if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  12319.                     return $this->raiseError('%s requires PHP extension "' . $dep['name'] .
  12320.                         '"' . $extra);
  12321.                 }
  12322.                     return $this->warning('warning: %s requires PHP extension "' . $dep['name'] .
  12323.                         '"' . $extra);
  12324.             }
  12325.         }
  12326.         $version = (string) $this->phpversion($dep['name']);
  12327.         if (empty($version)) {
  12328.             $version = '0';
  12329.         }
  12330.         $fail = false;
  12331.         if (isset($dep['min'])) {
  12332.             if (!version_compare($version, $dep['min'], '>=')) {
  12333.                 $fail = true;
  12334.             }
  12335.         }
  12336.         if (isset($dep['max'])) {
  12337.             if (!version_compare($version, $dep['max'], '<=')) {
  12338.                 $fail = true;
  12339.             }
  12340.         }
  12341.         if ($fail && !isset($dep['conflicts'])) {
  12342.             if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  12343.                 return $this->raiseError('%s requires PHP extension "' . $dep['name'] .
  12344.                     '"' . $extra . ', installed version is ' . $version);
  12345.             } else {
  12346.                 return $this->warning('warning: %s requires PHP extension "' . $dep['name'] .
  12347.                     '"' . $extra . ', installed version is ' . $version);
  12348.             }
  12349.         } elseif ((isset($dep['min']) || isset($dep['max'])) && !$fail && isset($dep['conflicts'])) {
  12350.             if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  12351.                 return $this->raiseError('%s conflicts with PHP extension "' .
  12352.                     $dep['name'] . '"' . $extra . ', installed version is ' . $version);
  12353.             } else {
  12354.                 return $this->warning('warning: %s conflicts with PHP extension "' .
  12355.                     $dep['name'] . '"' . $extra . ', installed version is ' . $version);
  12356.             }
  12357.         }
  12358.         if (isset($dep['exclude'])) {
  12359.             foreach ($dep['exclude'] as $exclude) {
  12360.                 if (version_compare($version, $exclude, '==')) {
  12361.                     if (isset($dep['conflicts'])) {
  12362.                         continue;
  12363.                     }
  12364.                     if (!isset($this->_options['nodeps']) &&
  12365.                           !isset($this->_options['force'])) {
  12366.                         return $this->raiseError('%s is not compatible with PHP extension "' .
  12367.                             $dep['name'] . '" version ' .
  12368.                             $exclude);
  12369.                     } else {
  12370.                         return $this->warning('warning: %s is not compatible with PHP extension "' .
  12371.                             $dep['name'] . '" version ' .
  12372.                             $exclude);
  12373.                     }
  12374.                 } elseif (version_compare($version, $exclude, '!=') && isset($dep['conflicts'])) {
  12375.                     if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  12376.                         return $this->raiseError('%s conflicts with PHP extension "' .
  12377.                             $dep['name'] . '"' . $extra . ', installed version is ' . $version);
  12378.                     } else {
  12379.                         return $this->warning('warning: %s conflicts with PHP extension "' .
  12380.                             $dep['name'] . '"' . $extra . ', installed version is ' . $version);
  12381.                     }
  12382.                 }
  12383.             }
  12384.         }
  12385.         if (isset($dep['recommended'])) {
  12386.             if (version_compare($version, $dep['recommended'], '==')) {
  12387.                 return true;
  12388.             } else {
  12389.                 if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  12390.                     return $this->raiseError('%s dependency: PHP extension ' . $dep['name'] .
  12391.                         ' version "' . $version . '"' .
  12392.                         ' is not the recommended version "' . $dep['recommended'] .
  12393.                         '", but may be compatible, use --force to install');
  12394.                 } else {
  12395.                     return $this->warning('warning: %s dependency: PHP extension ' .
  12396.                         $dep['name'] . ' version "' . $version . '"' .
  12397.                         ' is not the recommended version "' . $dep['recommended'].'"');
  12398.                 }
  12399.             }
  12400.         }
  12401.         return true;
  12402.     }
  12403.  
  12404.     function validatePhpDependency($dep)
  12405.     {
  12406.         if ($this->_state != PEAR_VALIDATE_INSTALLING &&
  12407.               $this->_state != PEAR_VALIDATE_DOWNLOADING) {
  12408.             return true;
  12409.         }
  12410.         $version = $this->phpversion();
  12411.         $extra = $this->_getExtraString($dep);
  12412.         if (isset($dep['exclude'])) {
  12413.             if (!is_array($dep['exclude'])) {
  12414.                 $dep['exclude'] = array($dep['exclude']);
  12415.             }
  12416.         }
  12417.         if (isset($dep['min'])) {
  12418.             if (!version_compare($version, $dep['min'], '>=')) {
  12419.                 if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  12420.                     return $this->raiseError('%s requires PHP' .
  12421.                         $extra . ', installed version is ' . $version);
  12422.                 } else {
  12423.                     return $this->warning('warning: %s requires PHP' .
  12424.                         $extra . ', installed version is ' . $version);
  12425.                 }
  12426.             }
  12427.         }
  12428.         if (isset($dep['max'])) {
  12429.             if (!version_compare($version, $dep['max'], '<=')) {
  12430.                 if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  12431.                     return $this->raiseError('%s requires PHP' .
  12432.                         $extra . ', installed version is ' . $version);
  12433.                 } else {
  12434.                     return $this->warning('warning: %s requires PHP' .
  12435.                         $extra . ', installed version is ' . $version);
  12436.                 }
  12437.             }
  12438.         }
  12439.         if (isset($dep['exclude'])) {
  12440.             foreach ($dep['exclude'] as $exclude) {
  12441.                 if (version_compare($version, $exclude, '==')) {
  12442.                     if (!isset($this->_options['nodeps']) &&
  12443.                           !isset($this->_options['force'])) {
  12444.                         return $this->raiseError('%s is not compatible with PHP version ' .
  12445.                             $exclude);
  12446.                     } else {
  12447.                         return $this->warning(
  12448.                             'warning: %s is not compatible with PHP version ' .
  12449.                             $exclude);
  12450.                     }
  12451.                 }
  12452.             }
  12453.         }
  12454.         return true;
  12455.     }
  12456.  
  12457.     /**
  12458.      * This makes unit-testing a heck of a lot easier
  12459.      */
  12460.     function getPEARVersion()
  12461.     {
  12462.         return '1.7.1';
  12463.     }
  12464.  
  12465.     function validatePearinstallerDependency($dep)
  12466.     {
  12467.         $pearversion = $this->getPEARVersion();
  12468.         $extra = $this->_getExtraString($dep);
  12469.         if (isset($dep['exclude'])) {
  12470.             if (!is_array($dep['exclude'])) {
  12471.                 $dep['exclude'] = array($dep['exclude']);
  12472.             }
  12473.         }
  12474.         if (version_compare($pearversion, $dep['min'], '<')) {
  12475.             if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  12476.                 return $this->raiseError('%s requires PEAR Installer' . $extra .
  12477.                     ', installed version is ' . $pearversion);
  12478.             } else {
  12479.                 return $this->warning('warning: %s requires PEAR Installer' . $extra .
  12480.                     ', installed version is ' . $pearversion);
  12481.             }
  12482.         }
  12483.         if (isset($dep['max'])) {
  12484.             if (version_compare($pearversion, $dep['max'], '>')) {
  12485.                 if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  12486.                     return $this->raiseError('%s requires PEAR Installer' . $extra .
  12487.                         ', installed version is ' . $pearversion);
  12488.                 } else {
  12489.                     return $this->warning('warning: %s requires PEAR Installer' . $extra .
  12490.                         ', installed version is ' . $pearversion);
  12491.                 }
  12492.             }
  12493.         }
  12494.         if (isset($dep['exclude'])) {
  12495.             if (!isset($dep['exclude'][0])) {
  12496.                 $dep['exclude'] = array($dep['exclude']);
  12497.             }
  12498.             foreach ($dep['exclude'] as $exclude) {
  12499.                 if (version_compare($exclude, $pearversion, '==')) {
  12500.                     if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  12501.                         return $this->raiseError('%s is not compatible with PEAR Installer ' .
  12502.                             'version ' . $exclude);
  12503.                     } else {
  12504.                         return $this->warning('warning: %s is not compatible with PEAR ' .
  12505.                             'Installer version ' . $exclude);
  12506.                     }
  12507.                 }
  12508.             }
  12509.         }
  12510.         return true;
  12511.     }
  12512.  
  12513.     function validateSubpackageDependency($dep, $required, $params)
  12514.     {
  12515.         return $this->validatePackageDependency($dep, $required, $params);
  12516.     }
  12517.  
  12518.     /**
  12519.      * @param array dependency information (2.0 format)
  12520.      * @param boolean whether this is a required dependency
  12521.      * @param array a list of downloaded packages to be installed, if any
  12522.      * @param boolean if true, then deps on pear.php.net that fail will also check
  12523.      *                against pecl.php.net packages to accomodate extensions that have
  12524.      *                moved to pecl.php.net from pear.php.net
  12525.      */
  12526.     function validatePackageDependency($dep, $required, $params, $depv1 = false)
  12527.     {
  12528.         if ($this->_state != PEAR_VALIDATE_INSTALLING &&
  12529.               $this->_state != PEAR_VALIDATE_DOWNLOADING) {
  12530.             return true;
  12531.         }
  12532.         if (isset($dep['providesextension'])) {
  12533.             if ($this->extension_loaded($dep['providesextension'])) {
  12534.                 $save = $dep;
  12535.                 $subdep = $dep;
  12536.                 $subdep['name'] = $subdep['providesextension'];
  12537.                 PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  12538.                 $ret = $this->validateExtensionDependency($subdep, $required);
  12539.                 PEAR::popErrorHandling();
  12540.                 if (!PEAR::isError($ret)) {
  12541.                     return true;
  12542.                 }
  12543.             }
  12544.         }
  12545.         if ($this->_state == PEAR_VALIDATE_INSTALLING) {
  12546.             return $this->_validatePackageInstall($dep, $required, $depv1);
  12547.         }
  12548.         if ($this->_state == PEAR_VALIDATE_DOWNLOADING) {
  12549.             return $this->_validatePackageDownload($dep, $required, $params, $depv1);
  12550.         }
  12551.     }
  12552.  
  12553.     function _validatePackageDownload($dep, $required, $params, $depv1 = false)
  12554.     {
  12555.         $dep['package'] = $dep['name'];
  12556.         if (isset($dep['uri'])) {
  12557.             $dep['channel'] = '__uri';
  12558.         }
  12559.         $depname = $this->_registry->parsedPackageNameToString($dep, true);
  12560.         $found = false;
  12561.         foreach ($params as $param) {
  12562.             if ($param->isEqual(
  12563.                   array('package' => $dep['name'],
  12564.                         'channel' => $dep['channel']))) {
  12565.                 $found = true;
  12566.                 break;
  12567.             }
  12568.             if ($depv1 && $dep['channel'] == 'pear.php.net') {
  12569.                 if ($param->isEqual(
  12570.                   array('package' => $dep['name'],
  12571.                         'channel' => 'pecl.php.net'))) {
  12572.                     $found = true;
  12573.                     break;
  12574.                 }
  12575.             }
  12576.         }
  12577.         if (!$found && isset($dep['providesextension'])) {
  12578.             foreach ($params as $param) {
  12579.                 if ($param->isExtension($dep['providesextension'])) {
  12580.                     $found = true;
  12581.                     break;
  12582.                 }
  12583.             }
  12584.         }
  12585.         if ($found) {
  12586.             $version = $param->getVersion();
  12587.             $installed = false;
  12588.             $downloaded = true;
  12589.         } else {
  12590.             if ($this->_registry->packageExists($dep['name'], $dep['channel'])) {
  12591.                 $installed = true;
  12592.                 $downloaded = false;
  12593.                 $version = $this->_registry->packageinfo($dep['name'], 'version',
  12594.                     $dep['channel']);
  12595.             } else {
  12596.                 if ($dep['channel'] == 'pecl.php.net' && $this->_registry->packageExists($dep['name'],
  12597.                       'pear.php.net')) {
  12598.                     $installed = true;
  12599.                     $downloaded = false;
  12600.                     $version = $this->_registry->packageinfo($dep['name'], 'version',
  12601.                         'pear.php.net');
  12602.                 } else {
  12603.                     $version = 'not installed or downloaded';
  12604.                     $installed = false;
  12605.                     $downloaded = false;
  12606.                 }
  12607.             }
  12608.         }
  12609.         $extra = $this->_getExtraString($dep);
  12610.         if (isset($dep['exclude'])) {
  12611.             if (!is_array($dep['exclude'])) {
  12612.                 $dep['exclude'] = array($dep['exclude']);
  12613.             }
  12614.         }
  12615.         if (!isset($dep['min']) && !isset($dep['max']) &&
  12616.               !isset($dep['recommended']) && !isset($dep['exclude'])) {
  12617.             if ($installed || $downloaded) {
  12618.                 $installed = $installed ? 'installed' : 'downloaded';
  12619.                 if (isset($dep['conflicts'])) {
  12620.                     if ($version) {
  12621.                         $rest = ", $installed version is " . $version;
  12622.                     } else {
  12623.                         $rest = '';
  12624.                     }
  12625.                     if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  12626.                         return $this->raiseError('%s conflicts with package "' . $depname . '"' .
  12627.                             $extra . $rest);
  12628.                     } else {
  12629.                         return $this->warning('warning: %s conflicts with package "' . $depname . '"' .
  12630.                             $extra . $rest);
  12631.                     }
  12632.                 }
  12633.                 return true;
  12634.             } else {
  12635.                 if (isset($dep['conflicts'])) {
  12636.                     return true;
  12637.                 }
  12638.                 if ($required) {
  12639.                     if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  12640.                         return $this->raiseError('%s requires package "' . $depname . '"' .
  12641.                             $extra);
  12642.                     } else {
  12643.                         return $this->warning('warning: %s requires package "' . $depname . '"' .
  12644.                             $extra);
  12645.                     }
  12646.                 } else {
  12647.                     return $this->warning('%s can optionally use package "' . $depname . '"' .
  12648.                         $extra);
  12649.                 }
  12650.             }
  12651.         }
  12652.         if (!$installed && !$downloaded) {
  12653.             if (isset($dep['conflicts'])) {
  12654.                 return true;
  12655.             }
  12656.             if ($required) {
  12657.                 if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  12658.                     return $this->raiseError('%s requires package "' . $depname . '"' .
  12659.                         $extra);
  12660.                 } else {
  12661.                     return $this->warning('warning: %s requires package "' . $depname . '"' .
  12662.                         $extra);
  12663.                 }
  12664.             } else {
  12665.                 return $this->warning('%s can optionally use package "' . $depname . '"' .
  12666.                     $extra);
  12667.             }
  12668.         }
  12669.         $fail = false;
  12670.         if (isset($dep['min'])) {
  12671.             if (version_compare($version, $dep['min'], '<')) {
  12672.                 $fail = true;
  12673.             }
  12674.         }
  12675.         if (isset($dep['max'])) {
  12676.             if (version_compare($version, $dep['max'], '>')) {
  12677.                 $fail = true;
  12678.             }
  12679.         }
  12680.         if ($fail && !isset($dep['conflicts'])) {
  12681.             $installed = $installed ? 'installed' : 'downloaded';
  12682.             $dep['package'] = $dep['name'];
  12683.             $dep = $this->_registry->parsedPackageNameToString($dep, true);
  12684.             if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  12685.                 return $this->raiseError('%s requires package "' . $depname . '"' .
  12686.                     $extra . ", $installed version is " . $version);
  12687.             } else {
  12688.                 return $this->warning('warning: %s requires package "' . $depname . '"' .
  12689.                     $extra . ", $installed version is " . $version);
  12690.             }
  12691.         } elseif ((isset($dep['min']) || isset($dep['max'])) && !$fail &&
  12692.               isset($dep['conflicts']) && !isset($dep['exclude'])) {
  12693.             $installed = $installed ? 'installed' : 'downloaded';
  12694.             if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  12695.                 return $this->raiseError('%s conflicts with package "' . $depname . '"' . $extra .
  12696.                     ", $installed version is " . $version);
  12697.             } else {
  12698.                 return $this->warning('warning: %s conflicts with package "' . $depname . '"' .
  12699.                     $extra . ", $installed version is " . $version);
  12700.             }
  12701.         }
  12702.         if (isset($dep['exclude'])) {
  12703.             $installed = $installed ? 'installed' : 'downloaded';
  12704.             foreach ($dep['exclude'] as $exclude) {
  12705.                 if (version_compare($version, $exclude, '==') && !isset($dep['conflicts'])) {
  12706.                     if (!isset($this->_options['nodeps']) &&
  12707.                           !isset($this->_options['force'])) {
  12708.                         return $this->raiseError('%s is not compatible with ' .
  12709.                             $installed . ' package "' .
  12710.                             $depname . '" version ' .
  12711.                             $exclude);
  12712.                     } else {
  12713.                         return $this->warning('warning: %s is not compatible with ' .
  12714.                             $installed . ' package "' .
  12715.                             $depname . '" version ' .
  12716.                             $exclude);
  12717.                     }
  12718.                 } elseif (version_compare($version, $exclude, '!=') && isset($dep['conflicts'])) {
  12719.                     $installed = $installed ? 'installed' : 'downloaded';
  12720.                     if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  12721.                         return $this->raiseError('%s conflicts with package "' . $depname . '"' .
  12722.                             $extra . ", $installed version is " . $version);
  12723.                     } else {
  12724.                         return $this->warning('warning: %s conflicts with package "' . $depname . '"' .
  12725.                             $extra . ", $installed version is " . $version);
  12726.                     }
  12727.                 }
  12728.             }
  12729.         }
  12730.         if (isset($dep['recommended'])) {
  12731.             $installed = $installed ? 'installed' : 'downloaded';
  12732.             if (version_compare($version, $dep['recommended'], '==')) {
  12733.                 return true;
  12734.             } else {
  12735.                 if (!$found && $installed) {
  12736.                     $param = $this->_registry->getPackage($dep['name'], $dep['channel']);
  12737.                 }
  12738.                 if ($param) {
  12739.                     $found = false;
  12740.                     foreach ($params as $parent) {
  12741.                         if ($parent->isEqual($this->_currentPackage)) {
  12742.                             $found = true;
  12743.                             break;
  12744.                         }
  12745.                     }
  12746.                     if ($found) {
  12747.                         if ($param->isCompatible($parent)) {
  12748.                             return true;
  12749.                         }
  12750.                     } else { // this is for validPackage() calls
  12751.                         $parent = $this->_registry->getPackage($this->_currentPackage['package'],
  12752.                             $this->_currentPackage['channel']);
  12753.                         if ($parent !== null) {
  12754.                             if ($param->isCompatible($parent)) {
  12755.                                 return true;
  12756.                             }
  12757.                         }
  12758.                     }
  12759.                 }
  12760.                 if (!isset($this->_options['nodeps']) && !isset($this->_options['force']) &&
  12761.                       !isset($this->_options['loose'])) {
  12762.                     return $this->raiseError('%s dependency package "' . $depname .
  12763.                         '" ' . $installed . ' version ' . $version . 
  12764.                         ' is not the recommended version ' . $dep['recommended'] .
  12765.                         ', but may be compatible, use --force to install');
  12766.                 } else {
  12767.                     return $this->warning('warning: %s dependency package "' . $depname .
  12768.                         '" ' . $installed . ' version ' . $version .
  12769.                         ' is not the recommended version ' . $dep['recommended']);
  12770.                 }
  12771.             }
  12772.         }
  12773.         return true;
  12774.     }
  12775.  
  12776.     function _validatePackageInstall($dep, $required, $depv1 = false)
  12777.     {
  12778.         return $this->_validatePackageDownload($dep, $required, array(), $depv1);
  12779.     }
  12780.  
  12781.     /**
  12782.      * Verify that uninstalling packages passed in to command line is OK.
  12783.      *
  12784.      * @param PEAR_Installer $dl
  12785.      * @return PEAR_Error|true
  12786.      */
  12787.     function validatePackageUninstall(&$dl)
  12788.     {
  12789.         if (PEAR::isError($this->_dependencydb)) {
  12790.             return $this->_dependencydb;
  12791.         }
  12792.         $params = array();
  12793.         // construct an array of "downloaded" packages to fool the package dependency checker
  12794.         // into using these to validate uninstalls of circular dependencies
  12795.         $downloaded = &$dl->getUninstallPackages();
  12796.         foreach ($downloaded as $i => $pf) {
  12797.             if (!class_exists('PEAR_Downloader_Package')) {
  12798.                 require_once 'phar://go-pear.phar/' . 'PEAR/Downloader/Package.php';
  12799.             }
  12800.             $dp = &new PEAR_Downloader_Package($dl);
  12801.             $dp->setPackageFile($downloaded[$i]);
  12802.             $params[$i] = &$dp;
  12803.         }
  12804.         // check cache
  12805.         $memyselfandI = strtolower($this->_currentPackage['channel']) . '/' .
  12806.             strtolower($this->_currentPackage['package']);
  12807.         if (isset($dl->___uninstall_package_cache)) {
  12808.             $badpackages = $dl->___uninstall_package_cache;
  12809.             if (isset($badpackages[$memyselfandI]['warnings'])) {
  12810.                 foreach ($badpackages[$memyselfandI]['warnings'] as $warning) {
  12811.                     $dl->log(0, $warning[0]);
  12812.                 }
  12813.             }
  12814.             if (isset($badpackages[$memyselfandI]['errors'])) {
  12815.                 foreach ($badpackages[$memyselfandI]['errors'] as $error) {
  12816.                     if (is_array($error)) {
  12817.                         $dl->log(0, $error[0]);
  12818.                     } else {
  12819.                         $dl->log(0, $error->getMessage());
  12820.                     }
  12821.                 }
  12822.                 if (isset($this->_options['nodeps']) || isset($this->_options['force'])) {
  12823.                     return $this->warning(
  12824.                         'warning: %s should not be uninstalled, other installed packages depend ' .
  12825.                         'on this package');
  12826.                 } else {
  12827.                     return $this->raiseError(
  12828.                         '%s cannot be uninstalled, other installed packages depend on this package');
  12829.                 }
  12830.             }
  12831.             return true;
  12832.         }
  12833.         // first, list the immediate parents of each package to be uninstalled
  12834.         $perpackagelist = array();
  12835.         $allparents = array();
  12836.         foreach ($params as $i => $param) {
  12837.             $a = array('channel' => strtolower($param->getChannel()),
  12838.                       'package' => strtolower($param->getPackage()));
  12839.             $deps = $this->_dependencydb->getDependentPackages($a);
  12840.             if ($deps) {
  12841.                 foreach ($deps as $d) {
  12842.                     $pardeps = $this->_dependencydb->getDependencies($d);
  12843.                     foreach ($pardeps as $dep) {
  12844.                         if (strtolower($dep['dep']['channel']) == $a['channel'] &&
  12845.                               strtolower($dep['dep']['name']) == $a['package']) {
  12846.                             if (!isset($perpackagelist[$a['channel'] . '/' . $a['package']])) {
  12847.                                 $perpackagelist[$a['channel'] . '/' . $a['package']] = array();
  12848.                             }
  12849.                             $perpackagelist[$a['channel'] . '/' . $a['package']][]
  12850.                                 = array($d['channel'] . '/' . $d['package'], $dep);
  12851.                             if (!isset($allparents[$d['channel'] . '/' . $d['package']])) {
  12852.                                 $allparents[$d['channel'] . '/' . $d['package']] = array();
  12853.                             }
  12854.                             if (!isset($allparents[$d['channel'] . '/' . $d['package']][$a['channel'] . '/' . $a['package']])) {
  12855.                                 $allparents[$d['channel'] . '/' . $d['package']][$a['channel'] . '/' . $a['package']] = array();
  12856.                             }
  12857.                             $allparents[$d['channel'] . '/' . $d['package']]
  12858.                                        [$a['channel'] . '/' . $a['package']][]
  12859.                                 = array($d, $dep);
  12860.                         }
  12861.                     }
  12862.                 }
  12863.             }
  12864.         }
  12865.         // next, remove any packages from the parents list that are not installed
  12866.         $remove = array();
  12867.         foreach ($allparents as $parent => $d1) {
  12868.             foreach ($d1 as $d) {
  12869.                 if ($this->_registry->packageExists($d[0][0]['package'], $d[0][0]['channel'])) {
  12870.                     continue;
  12871.                 }
  12872.                 $remove[$parent] = true;
  12873.             }
  12874.         }
  12875.         // next remove any packages from the parents list that are not passed in for
  12876.         // uninstallation
  12877.         foreach ($allparents as $parent => $d1) {
  12878.             foreach ($d1 as $d) {
  12879.                 foreach ($params as $param) {
  12880.                     if (strtolower($param->getChannel()) == $d[0][0]['channel'] &&
  12881.                           strtolower($param->getPackage()) == $d[0][0]['package']) {
  12882.                         // found it
  12883.                         continue 3;
  12884.                     }
  12885.                 }
  12886.                 $remove[$parent] = true;
  12887.             }
  12888.         }
  12889.         // remove all packages whose dependencies fail
  12890.         // save which ones failed for error reporting
  12891.         $badchildren = array();
  12892.         do {
  12893.             $fail = false;
  12894.             foreach ($remove as $package => $unused) {
  12895.                 if (!isset($allparents[$package])) {
  12896.                     continue;
  12897.                 }
  12898.                 foreach ($allparents[$package] as $kid => $d1) {
  12899.                     foreach ($d1 as $depinfo) {
  12900.                         if ($depinfo[1]['type'] != 'optional') {
  12901.                             if (isset($badchildren[$kid])) {
  12902.                                 continue;
  12903.                             }
  12904.                             $badchildren[$kid] = true;
  12905.                             $remove[$kid] = true;
  12906.                             $fail = true;
  12907.                             continue 2;
  12908.                         }
  12909.                     }
  12910.                 }
  12911.                 if ($fail) {
  12912.                     // start over, we removed some children
  12913.                     continue 2;
  12914.                 }
  12915.             }
  12916.         } while ($fail);
  12917.         // next, construct the list of packages that can't be uninstalled
  12918.         $badpackages = array();
  12919.         $save = $this->_currentPackage;
  12920.         foreach ($perpackagelist as $package => $packagedeps) {
  12921.             foreach ($packagedeps as $parent) {
  12922.                 if (!isset($remove[$parent[0]])) {
  12923.                     continue;
  12924.                 }
  12925.                 $packagename = $this->_registry->parsePackageName($parent[0]);
  12926.                 $packagename['channel'] = $this->_registry->channelAlias($packagename['channel']);
  12927.                 $pa = $this->_registry->getPackage($packagename['package'], $packagename['channel']);
  12928.                 $packagename['package'] = $pa->getPackage();
  12929.                 $this->_currentPackage = $packagename;
  12930.                 // parent is not present in uninstall list, make sure we can actually
  12931.                 // uninstall it (parent dep is optional)
  12932.                 $parentname['channel'] = $this->_registry->channelAlias($parent[1]['dep']['channel']);
  12933.                 $pa = $this->_registry->getPackage($parent[1]['dep']['name'], $parent[1]['dep']['channel']);
  12934.                 $parentname['package'] = $pa->getPackage();
  12935.                 $parent[1]['dep']['package'] = $parentname['package'];
  12936.                 $parent[1]['dep']['channel'] = $parentname['channel'];
  12937.                 if ($parent[1]['type'] == 'optional') {
  12938.                     $test = $this->_validatePackageUninstall($parent[1]['dep'], false, $dl);
  12939.                     if ($test !== true) {
  12940.                         $badpackages[$package]['warnings'][] = $test;
  12941.                     }
  12942.                 } else {
  12943.                     $test = $this->_validatePackageUninstall($parent[1]['dep'], true, $dl);
  12944.                     if ($test !== true) {
  12945.                         $badpackages[$package]['errors'][] = $test;
  12946.                     }
  12947.                 }
  12948.             }
  12949.         }
  12950.         $this->_currentPackage = $save;
  12951.         $dl->___uninstall_package_cache = $badpackages;
  12952.         if (isset($badpackages[$memyselfandI])) {
  12953.             if (isset($badpackages[$memyselfandI]['warnings'])) {
  12954.                 foreach ($badpackages[$memyselfandI]['warnings'] as $warning) {
  12955.                     $dl->log(0, $warning[0]);
  12956.                 }
  12957.             }
  12958.             if (isset($badpackages[$memyselfandI]['errors'])) {
  12959.                 foreach ($badpackages[$memyselfandI]['errors'] as $error) {
  12960.                     if (is_array($error)) {
  12961.                         $dl->log(0, $error[0]);
  12962.                     } else {
  12963.                         $dl->log(0, $error->getMessage());
  12964.                     }
  12965.                 }
  12966.                 if (isset($this->_options['nodeps']) || isset($this->_options['force'])) {
  12967.                     return $this->warning(
  12968.                         'warning: %s should not be uninstalled, other installed packages depend ' .
  12969.                         'on this package');
  12970.                 } else {
  12971.                     return $this->raiseError(
  12972.                         '%s cannot be uninstalled, other installed packages depend on this package');
  12973.                 }
  12974.             }
  12975.         }
  12976.         return true;
  12977.     }
  12978.  
  12979.     function _validatePackageUninstall($dep, $required, $dl)
  12980.     {
  12981.         $depname = $this->_registry->parsedPackageNameToString($dep, true);
  12982.         $version = $this->_registry->packageinfo($dep['package'], 'version',
  12983.             $dep['channel']);
  12984.         if (!$version) {
  12985.             return true;
  12986.         }
  12987.         $extra = $this->_getExtraString($dep);
  12988.         if (isset($dep['exclude'])) {
  12989.             if (!is_array($dep['exclude'])) {
  12990.                 $dep['exclude'] = array($dep['exclude']);
  12991.             }
  12992.         }
  12993.         if (isset($dep['conflicts'])) {
  12994.             return true; // uninstall OK - these packages conflict (probably installed with --force)
  12995.         }
  12996.         if (!isset($dep['min']) && !isset($dep['max'])) {
  12997.             if ($required) {
  12998.                 if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  12999.                     return $this->raiseError('"' . $depname . '" is required by ' .
  13000.                         'installed package %s' . $extra);
  13001.                 } else {
  13002.                     return $this->warning('warning: "' . $depname . '" is required by ' .
  13003.                         'installed package %s' . $extra);
  13004.                 }
  13005.             } else {
  13006.                 return $this->warning('"' . $depname . '" can be optionally used by ' .
  13007.                         'installed package %s' . $extra);
  13008.             }
  13009.         }
  13010.         $fail = false;
  13011.         if (isset($dep['min'])) {
  13012.             if (version_compare($version, $dep['min'], '>=')) {
  13013.                 $fail = true;
  13014.             }
  13015.         }
  13016.         if (isset($dep['max'])) {
  13017.             if (version_compare($version, $dep['max'], '<=')) {
  13018.                 $fail = true;
  13019.             }
  13020.         }
  13021.         // we re-use this variable, preserve the original value
  13022.         $saverequired = $required;
  13023.         if ($required) {
  13024.             if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  13025.                 return $this->raiseError($depname . $extra . ' is required by installed package' .
  13026.                     ' "%s"');
  13027.             } else {
  13028.                 return $this->raiseError('warning: ' . $depname . $extra .
  13029.                     ' is required by installed package "%s"');
  13030.             }
  13031.         } else {
  13032.             return $this->warning($depname . $extra . ' can be optionally used by installed package' .
  13033.                     ' "%s"');
  13034.         }
  13035.         return true;
  13036.     }
  13037.  
  13038.     /**
  13039.      * validate a downloaded package against installed packages
  13040.      * 
  13041.      * As of PEAR 1.4.3, this will only validate
  13042.      *
  13043.      * @param array|PEAR_Downloader_Package|PEAR_PackageFile_v1|PEAR_PackageFile_v2
  13044.      *              $pkg package identifier (either
  13045.      *                   array('package' => blah, 'channel' => blah) or an array with
  13046.      *                   index 'info' referencing an object)
  13047.      * @param PEAR_Downloader $dl
  13048.      * @param array $params full list of packages to install
  13049.      * @return true|PEAR_Error
  13050.      */
  13051.     function validatePackage($pkg, &$dl, $params = array())
  13052.     {
  13053.         if (is_array($pkg) && isset($pkg['info'])) {
  13054.             $deps = $this->_dependencydb->getDependentPackageDependencies($pkg['info']);
  13055.         } else {
  13056.             $deps = $this->_dependencydb->getDependentPackageDependencies($pkg);
  13057.         }
  13058.         $fail = false;
  13059.         if ($deps) {
  13060.             if (!class_exists('PEAR_Downloader_Package')) {
  13061.                 require_once 'phar://go-pear.phar/' . 'PEAR/Downloader/Package.php';
  13062.             }
  13063.             $dp = &new PEAR_Downloader_Package($dl);
  13064.             if (is_object($pkg)) {
  13065.                 $dp->setPackageFile($pkg);
  13066.             } else {
  13067.                 $dp->setDownloadURL($pkg);
  13068.             }
  13069.             PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  13070.             foreach ($deps as $channel => $info) {
  13071.                 foreach ($info as $package => $ds) {
  13072.                     foreach ($params as $packd) {
  13073.                         if (strtolower($packd->getPackage()) == strtolower($package) &&
  13074.                               $packd->getChannel() == $channel) {
  13075.                             $dl->log(3, 'skipping installed package check of "' .
  13076.                                         $this->_registry->parsedPackageNameToString(
  13077.                                             array('channel' => $channel, 'package' => $package),
  13078.                                             true) .
  13079.                                         '", version "' . $packd->getVersion() . '" will be ' .
  13080.                                         'downloaded and installed');
  13081.                             continue 2; // jump to next package
  13082.                         }
  13083.                     }
  13084.                     foreach ($ds as $d) {
  13085.                         $checker = &new PEAR_Dependency2($this->_config, $this->_options,
  13086.                             array('channel' => $channel, 'package' => $package), $this->_state);
  13087.                         $dep = $d['dep'];
  13088.                         $required = $d['type'] == 'required';
  13089.                         $ret = $checker->_validatePackageDownload($dep, $required, array(&$dp));
  13090.                         if (is_array($ret)) {
  13091.                             $dl->log(0, $ret[0]);
  13092.                         } elseif (PEAR::isError($ret)) {
  13093.                             $dl->log(0, $ret->getMessage());
  13094.                             $fail = true;
  13095.                         }
  13096.                     }
  13097.                 }
  13098.             }
  13099.             PEAR::popErrorHandling();
  13100.         }
  13101.         if ($fail) {
  13102.             return $this->raiseError(
  13103.                 '%s cannot be installed, conflicts with installed packages');
  13104.         }
  13105.         return true;
  13106.     }
  13107.  
  13108.     /**
  13109.      * validate a package.xml 1.0 dependency
  13110.      */
  13111.     function validateDependency1($dep, $params = array())
  13112.     {
  13113.         if (!isset($dep['optional'])) {
  13114.             $dep['optional'] = 'no';
  13115.         }
  13116.         list($newdep, $type) = $this->normalizeDep($dep);
  13117.         if (!$newdep) {
  13118.             return $this->raiseError("Invalid Dependency");
  13119.         }
  13120.         if (method_exists($this, "validate{$type}Dependency")) {
  13121.             return $this->{"validate{$type}Dependency"}($newdep, $dep['optional'] == 'no',
  13122.                 $params, true);
  13123.         }
  13124.     }
  13125.  
  13126.     /**
  13127.      * Convert a 1.0 dep into a 2.0 dep
  13128.      */
  13129.     function normalizeDep($dep)
  13130.     {
  13131.         $types = array(
  13132.             'pkg' => 'Package',
  13133.             'ext' => 'Extension',
  13134.             'os' => 'Os',
  13135.             'php' => 'Php'
  13136.         );
  13137.         if (isset($types[$dep['type']])) {
  13138.             $type = $types[$dep['type']];
  13139.         } else {
  13140.             return array(false, false);
  13141.         }
  13142.         $newdep = array();
  13143.         switch ($type) {
  13144.             case 'Package' :
  13145.                 $newdep['channel'] = 'pear.php.net';
  13146.             case 'Extension' :
  13147.             case 'Os' :
  13148.                 $newdep['name'] = $dep['name'];
  13149.             break;
  13150.         }
  13151.         $dep['rel'] = PEAR_Dependency2::signOperator($dep['rel']);
  13152.         switch ($dep['rel']) {
  13153.             case 'has' :
  13154.                 return array($newdep, $type);
  13155.             break;
  13156.             case 'not' :
  13157.                 $newdep['conflicts'] = true;
  13158.             break;
  13159.             case '>=' :
  13160.             case '>' :
  13161.                 $newdep['min'] = $dep['version'];
  13162.                 if ($dep['rel'] == '>') {
  13163.                     $newdep['exclude'] = $dep['version'];
  13164.                 }
  13165.             break;
  13166.             case '<=' :
  13167.             case '<' :
  13168.                 $newdep['max'] = $dep['version'];
  13169.                 if ($dep['rel'] == '<') {
  13170.                     $newdep['exclude'] = $dep['version'];
  13171.                 }
  13172.             break;
  13173.             case 'ne' :
  13174.             case '!=' :
  13175.                 $newdep['min'] = '0';
  13176.                 $newdep['max'] = '100000';
  13177.                 $newdep['exclude'] = $dep['version'];
  13178.             break;
  13179.             case '==' :
  13180.                 $newdep['min'] = $dep['version'];
  13181.                 $newdep['max'] = $dep['version'];
  13182.             break;
  13183.         }
  13184.         if ($type == 'Php') {
  13185.             if (!isset($newdep['min'])) {
  13186.                 $newdep['min'] = '4.2.0';
  13187.             }
  13188.             if (!isset($newdep['max'])) {
  13189.                 $newdep['max'] = '6.0.0';
  13190.             }
  13191.         }
  13192.         return array($newdep, $type);
  13193.     }
  13194.  
  13195.     /**
  13196.      * Converts text comparing operators to them sign equivalents
  13197.      *
  13198.      * Example: 'ge' to '>='
  13199.      *
  13200.      * @access public
  13201.      * @param  string Operator
  13202.      * @return string Sign equivalent
  13203.      */
  13204.     function signOperator($operator)
  13205.     {
  13206.         switch($operator) {
  13207.             case 'lt': return '<';
  13208.             case 'le': return '<=';
  13209.             case 'gt': return '>';
  13210.             case 'ge': return '>=';
  13211.             case 'eq': return '==';
  13212.             case 'ne': return '!=';
  13213.             default:
  13214.                 return $operator;
  13215.         }
  13216.     }
  13217.  
  13218.     function raiseError($msg)
  13219.     {
  13220.         if (isset($this->_options['ignore-errors'])) {
  13221.             return $this->warning($msg);
  13222.         }
  13223.         return PEAR::raiseError(sprintf($msg, $this->_registry->parsedPackageNameToString(
  13224.             $this->_currentPackage, true)));
  13225.     }
  13226.  
  13227.     function warning($msg)
  13228.     {
  13229.         return array(sprintf($msg, $this->_registry->parsedPackageNameToString(
  13230.             $this->_currentPackage, true)));
  13231.     }
  13232. }
  13233. ?><?php
  13234. /**
  13235.  * PEAR_DependencyDB, advanced installed packages dependency database
  13236.  *
  13237.  * PHP versions 4 and 5
  13238.  *
  13239.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  13240.  * that is available through the world-wide-web at the following URI:
  13241.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  13242.  * the PHP License and are unable to obtain it through the web, please
  13243.  * send a note to license@php.net so we can mail you a copy immediately.
  13244.  *
  13245.  * @category   pear
  13246.  * @package    PEAR
  13247.  * @author     Tomas V. V. Cox <cox@idecnet.com>
  13248.  * @author     Greg Beaver <cellog@php.net>
  13249.  * @copyright  1997-2008 The PHP Group
  13250.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  13251.  * @version    CVS: $Id: DependencyDB.php,v 1.37 2008/01/03 20:26:35 cellog Exp $
  13252.  * @link       http://pear.php.net/package/PEAR
  13253.  * @since      File available since Release 1.4.0a1
  13254.  */
  13255.  
  13256. /**
  13257.  * Needed for error handling
  13258.  */
  13259. require_once 'phar://go-pear.phar/' . 'PEAR.php';
  13260. require_once 'phar://go-pear.phar/' . 'PEAR/Config.php';
  13261.  
  13262. $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'] = array();
  13263. /**
  13264.  * Track dependency relationships between installed packages
  13265.  * @category   pear
  13266.  * @package    PEAR
  13267.  * @author     Greg Beaver <cellog@php.net>
  13268.  * @author     Tomas V.V.Cox <cox@idec.net.com>
  13269.  * @copyright  1997-2008 The PHP Group
  13270.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  13271.  * @version    Release: 1.7.1
  13272.  * @link       http://pear.php.net/package/PEAR
  13273.  * @since      Class available since Release 1.4.0a1
  13274.  */
  13275. class PEAR_DependencyDB
  13276. {
  13277.     // {{{ properties
  13278.  
  13279.     /**
  13280.      * This is initialized by {@link setConfig()}
  13281.      * @var PEAR_Config
  13282.      * @access private
  13283.      */
  13284.     var $_config;
  13285.     /**
  13286.      * This is initialized by {@link setConfig()}
  13287.      * @var PEAR_Registry
  13288.      * @access private
  13289.      */
  13290.     var $_registry;
  13291.     /**
  13292.      * Filename of the dependency DB (usually .depdb)
  13293.      * @var string
  13294.      * @access private
  13295.      */
  13296.     var $_depdb = false;
  13297.     /**
  13298.      * File name of the lockfile (usually .depdblock)
  13299.      * @var string
  13300.      * @access private
  13301.      */
  13302.     var $_lockfile = false;
  13303.     /**
  13304.      * Open file resource for locking the lockfile
  13305.      * @var resource|false
  13306.      * @access private
  13307.      */
  13308.     var $_lockFp = false;
  13309.     /**
  13310.      * API version of this class, used to validate a file on-disk
  13311.      * @var string
  13312.      * @access private
  13313.      */
  13314.     var $_version = '1.0';
  13315.     /**
  13316.      * Cached dependency database file
  13317.      * @var array|null
  13318.      * @access private
  13319.      */
  13320.     var $_cache;
  13321.  
  13322.     // }}}
  13323.     // {{{ & singleton()
  13324.  
  13325.     /**
  13326.      * Get a raw dependency database.  Calls setConfig() and assertDepsDB()
  13327.      * @param PEAR_Config
  13328.      * @param string|false full path to the dependency database, or false to use default
  13329.      * @return PEAR_DependencyDB|PEAR_Error
  13330.      * @static
  13331.      */
  13332.     function &singleton(&$config, $depdb = false)
  13333.     {
  13334.         if (!isset($GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE']
  13335.               [$config->get('php_dir', null, 'pear.php.net')])) {
  13336.             $a = new PEAR_DependencyDB;
  13337.             $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE']
  13338.               [$config->get('php_dir', null, 'pear.php.net')] = &$a;
  13339.             $a->setConfig($config, $depdb);
  13340.             if (PEAR::isError($e = $a->assertDepsDB())) {
  13341.                 return $e;
  13342.             }
  13343.         }
  13344.         return $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE']
  13345.               [$config->get('php_dir', null, 'pear.php.net')];
  13346.     }
  13347.  
  13348.     /**
  13349.      * Set up the registry/location of dependency DB
  13350.      * @param PEAR_Config|false
  13351.      * @param string|false full path to the dependency database, or false to use default
  13352.      */
  13353.     function setConfig(&$config, $depdb = false)
  13354.     {
  13355.         if (!$config) {
  13356.             $this->_config = &PEAR_Config::singleton();
  13357.         } else {
  13358.             $this->_config = &$config;
  13359.         }
  13360.         $this->_registry = &$this->_config->getRegistry();
  13361.         if (!$depdb) {
  13362.             $this->_depdb = $this->_config->get('php_dir', null, 'pear.php.net') .
  13363.                 DIRECTORY_SEPARATOR . '.depdb';
  13364.         } else {
  13365.             $this->_depdb = $depdb;
  13366.         }
  13367.         $this->_lockfile = dirname($this->_depdb) . DIRECTORY_SEPARATOR . '.depdblock';
  13368.     }
  13369.     // }}}
  13370.  
  13371.     function hasWriteAccess()
  13372.     {
  13373.         if (!file_exists($this->_depdb)) {
  13374.             $dir = $this->_depdb;
  13375.             while ($dir && $dir != '.') {
  13376.                 $dir = dirname($dir); // cd ..
  13377.                 if ($dir != '.' && file_exists($dir)) {
  13378.                     if (is_writeable($dir)) {
  13379.                         return true;
  13380.                     } else {
  13381.                         return false;
  13382.                     }
  13383.                 }
  13384.             }
  13385.             return false;
  13386.         }
  13387.         return is_writeable($this->_depdb);
  13388.     }
  13389.  
  13390.     // {{{ assertDepsDB()
  13391.  
  13392.     /**
  13393.      * Create the dependency database, if it doesn't exist.  Error if the database is
  13394.      * newer than the code reading it.
  13395.      * @return void|PEAR_Error
  13396.      */
  13397.     function assertDepsDB()
  13398.     {
  13399.         if (!is_file($this->_depdb)) {
  13400.             $this->rebuildDB();
  13401.         } else {
  13402.             $depdb = $this->_getDepDB();
  13403.             // Datatype format has been changed, rebuild the Deps DB
  13404.             if ($depdb['_version'] < $this->_version) {
  13405.                 $this->rebuildDB();
  13406.             }
  13407.             if ($depdb['_version']{0} > $this->_version{0}) {
  13408.                 return PEAR::raiseError('Dependency database is version ' .
  13409.                     $depdb['_version'] . ', and we are version ' .
  13410.                     $this->_version . ', cannot continue');
  13411.             }
  13412.         }
  13413.     }
  13414.  
  13415.     /**
  13416.      * Get a list of installed packages that depend on this package
  13417.      * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array
  13418.      * @return array|false
  13419.      */
  13420.     function getDependentPackages(&$pkg)
  13421.     {
  13422.         $data = $this->_getDepDB();
  13423.         if (is_object($pkg)) {
  13424.             $channel = strtolower($pkg->getChannel());
  13425.             $package = strtolower($pkg->getPackage());
  13426.         } else {
  13427.             $channel = strtolower($pkg['channel']);
  13428.             $package = strtolower($pkg['package']);
  13429.         }
  13430.         if (isset($data['packages'][$channel][$package])) {
  13431.             return $data['packages'][$channel][$package];
  13432.         }
  13433.         return false;
  13434.     }
  13435.  
  13436.     /**
  13437.      * Get a list of the actual dependencies of installed packages that depend on
  13438.      * a package.
  13439.      * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array
  13440.      * @return array|false
  13441.      */
  13442.     function getDependentPackageDependencies(&$pkg)
  13443.     {
  13444.         $data = $this->_getDepDB();
  13445.         if (is_object($pkg)) {
  13446.             $channel = strtolower($pkg->getChannel());
  13447.             $package = strtolower($pkg->getPackage());
  13448.         } else {
  13449.             $channel = strtolower($pkg['channel']);
  13450.             $package = strtolower($pkg['package']);
  13451.         }
  13452.         $depend = $this->getDependentPackages($pkg);
  13453.         if (!$depend) {
  13454.             return false;
  13455.         }
  13456.         $dependencies = array();
  13457.         foreach ($depend as $info) {
  13458.             $temp = $this->getDependencies($info);
  13459.             foreach ($temp as $dep) {
  13460.                 if (strtolower($dep['dep']['channel']) == strtolower($channel) &&
  13461.                       strtolower($dep['dep']['name']) == strtolower($package)) {
  13462.                     if (!isset($dependencies[$info['channel']])) {
  13463.                         $dependencies[$info['channel']] = array();
  13464.                     }
  13465.                     if (!isset($dependencies[$info['channel']][$info['package']])) {
  13466.                         $dependencies[$info['channel']][$info['package']] = array();
  13467.                     }
  13468.                     $dependencies[$info['channel']][$info['package']][] = $dep;
  13469.                 }
  13470.             }
  13471.         }
  13472.         return $dependencies;
  13473.     }
  13474.  
  13475.     /**
  13476.      * Get a list of dependencies of this installed package
  13477.      * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array
  13478.      * @return array|false
  13479.      */
  13480.     function getDependencies(&$pkg)
  13481.     {
  13482.         if (is_object($pkg)) {
  13483.             $channel = strtolower($pkg->getChannel());
  13484.             $package = strtolower($pkg->getPackage());
  13485.         } else {
  13486.             $channel = strtolower($pkg['channel']);
  13487.             $package = strtolower($pkg['package']);
  13488.         }
  13489.         $data = $this->_getDepDB();
  13490.         if (isset($data['dependencies'][$channel][$package])) {
  13491.             return $data['dependencies'][$channel][$package];
  13492.         }
  13493.         return false;
  13494.     }
  13495.  
  13496.     /**
  13497.      * Determine whether $parent depends on $child, near or deep
  13498.      * @param array|PEAR_PackageFile_v2|PEAR_PackageFile_v2
  13499.      * @param array|PEAR_PackageFile_v2|PEAR_PackageFile_v2
  13500.      */
  13501.     function dependsOn($parent, $child)
  13502.     {
  13503.         $c = array();
  13504.         $this->_getDepDB();
  13505.         return $this->_dependsOn($parent, $child, $c);
  13506.     }
  13507.     
  13508.     function _dependsOn($parent, $child, &$checked)
  13509.     {
  13510.         if (is_object($parent)) {
  13511.             $channel = strtolower($parent->getChannel());
  13512.             $package = strtolower($parent->getPackage());
  13513.         } else {
  13514.             $channel = strtolower($parent['channel']);
  13515.             $package = strtolower($parent['package']);
  13516.         }
  13517.         if (is_object($child)) {
  13518.             $depchannel = strtolower($child->getChannel());
  13519.             $deppackage = strtolower($child->getPackage());
  13520.         } else {
  13521.             $depchannel = strtolower($child['channel']);
  13522.             $deppackage = strtolower($child['package']);
  13523.         }
  13524.         if (isset($checked[$channel][$package][$depchannel][$deppackage])) {
  13525.             return false; // avoid endless recursion
  13526.         }
  13527.         $checked[$channel][$package][$depchannel][$deppackage] = true;
  13528.         if (!isset($this->_cache['dependencies'][$channel][$package])) {
  13529.             return false;
  13530.         }
  13531.         foreach ($this->_cache['dependencies'][$channel][$package] as $info) {
  13532.             if (isset($info['dep']['uri'])) {
  13533.                 if (is_object($child)) {
  13534.                     if ($info['dep']['uri'] == $child->getURI()) {
  13535.                         return true;
  13536.                     }
  13537.                 } elseif (isset($child['uri'])) {
  13538.                     if ($info['dep']['uri'] == $child['uri']) {
  13539.                         return true;
  13540.                     }
  13541.                 }
  13542.                 return false;
  13543.             }
  13544.             if (strtolower($info['dep']['channel']) == strtolower($depchannel) &&
  13545.                   strtolower($info['dep']['name']) == strtolower($deppackage)) {
  13546.                 return true;
  13547.             }
  13548.         }
  13549.         foreach ($this->_cache['dependencies'][$channel][$package] as $info) {
  13550.             if (isset($info['dep']['uri'])) {
  13551.                 if ($this->_dependsOn(array(
  13552.                         'uri' => $info['dep']['uri'],
  13553.                         'package' => $info['dep']['name']), $child, $checked)) {
  13554.                     return true;
  13555.                 }
  13556.             } else {
  13557.                 if ($this->_dependsOn(array(
  13558.                         'channel' => $info['dep']['channel'],
  13559.                         'package' => $info['dep']['name']), $child, $checked)) {
  13560.                     return true;
  13561.                 }
  13562.             }
  13563.         }
  13564.         return false;
  13565.     }
  13566.  
  13567.     /**
  13568.      * Register dependencies of a package that is being installed or upgraded
  13569.      * @param PEAR_PackageFile_v2|PEAR_PackageFile_v2
  13570.      */
  13571.     function installPackage(&$package)
  13572.     {
  13573.         $data = $this->_getDepDB();
  13574.         unset($this->_cache);
  13575.         $this->_setPackageDeps($data, $package);
  13576.         $this->_writeDepDB($data);
  13577.     }
  13578.  
  13579.     /**
  13580.      * Remove dependencies of a package that is being uninstalled, or upgraded.
  13581.      *
  13582.      * Upgraded packages first uninstall, then install
  13583.      * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array If an array, then it must have
  13584.      *        indices 'channel' and 'package'
  13585.      */
  13586.     function uninstallPackage(&$pkg)
  13587.     {
  13588.         $data = $this->_getDepDB();
  13589.         unset($this->_cache);
  13590.         if (is_object($pkg)) {
  13591.             $channel = strtolower($pkg->getChannel());
  13592.             $package = strtolower($pkg->getPackage());
  13593.         } else {
  13594.             $channel = strtolower($pkg['channel']);
  13595.             $package = strtolower($pkg['package']);
  13596.         }
  13597.         if (!isset($data['dependencies'][$channel][$package])) {
  13598.             return true;
  13599.         }
  13600.         foreach ($data['dependencies'][$channel][$package] as $dep) {
  13601.             $found = false;
  13602.             if (isset($dep['dep']['uri'])) {
  13603.                 $depchannel = '__uri';
  13604.             } else {
  13605.                 $depchannel = strtolower($dep['dep']['channel']);
  13606.             }
  13607.             if (isset($data['packages'][$depchannel][strtolower($dep['dep']['name'])])) {
  13608.                 foreach ($data['packages'][$depchannel][strtolower($dep['dep']['name'])] as
  13609.                       $i => $info) {
  13610.                     if ($info['channel'] == $channel &&
  13611.                           $info['package'] == $package) {
  13612.                         $found = true;
  13613.                         break;
  13614.                     }
  13615.                 }
  13616.             }
  13617.             if ($found) {
  13618.                 unset($data['packages'][$depchannel][strtolower($dep['dep']['name'])][$i]);
  13619.                 if (!count($data['packages'][$depchannel][strtolower($dep['dep']['name'])])) {
  13620.                     unset($data['packages'][$depchannel][strtolower($dep['dep']['name'])]);
  13621.                     if (!count($data['packages'][$depchannel])) {
  13622.                         unset($data['packages'][$depchannel]);
  13623.                     }
  13624.                 } else {
  13625.                     $data['packages'][$depchannel][strtolower($dep['dep']['name'])] =
  13626.                         array_values(
  13627.                             $data['packages'][$depchannel][strtolower($dep['dep']['name'])]);
  13628.                 }
  13629.             }
  13630.         }
  13631.         unset($data['dependencies'][$channel][$package]);
  13632.         if (!count($data['dependencies'][$channel])) {
  13633.             unset($data['dependencies'][$channel]);
  13634.         }
  13635.         if (!count($data['dependencies'])) {
  13636.             unset($data['dependencies']);
  13637.         }
  13638.         if (!count($data['packages'])) {
  13639.             unset($data['packages']);
  13640.         }
  13641.         $this->_writeDepDB($data);
  13642.     }
  13643.  
  13644.     /**
  13645.      * Rebuild the dependency DB by reading registry entries.
  13646.      * @return true|PEAR_Error
  13647.      */
  13648.     function rebuildDB()
  13649.     {
  13650.         $depdb = array('_version' => $this->_version);
  13651.         if (!$this->hasWriteAccess()) {
  13652.             // allow startup for read-only with older Registry
  13653.             return $depdb;
  13654.         }
  13655.         $packages = $this->_registry->listAllPackages();
  13656.         if (PEAR::isError($packages)) {
  13657.             return $packages;
  13658.         }
  13659.         foreach ($packages as $channel => $ps) {
  13660.             foreach ($ps as $package) {
  13661.                 $package = $this->_registry->getPackage($package, $channel);
  13662.                 if (PEAR::isError($package)) {
  13663.                     return $package;
  13664.                 }
  13665.                 $this->_setPackageDeps($depdb, $package);
  13666.             }
  13667.         }
  13668.         $error = $this->_writeDepDB($depdb);
  13669.         if (PEAR::isError($error)) {
  13670.             return $error;
  13671.         }
  13672.         $this->_cache = $depdb;
  13673.         return true;
  13674.     }
  13675.  
  13676.     /**
  13677.      * Register usage of the dependency DB to prevent race conditions
  13678.      * @param int one of the LOCK_* constants
  13679.      * @return true|PEAR_Error
  13680.      * @access private
  13681.      */
  13682.     function _lock($mode = LOCK_EX)
  13683.     {
  13684.         if (!eregi('Windows 9', php_uname())) {
  13685.             if ($mode != LOCK_UN && is_resource($this->_lockFp)) {
  13686.                 // XXX does not check type of lock (LOCK_SH/LOCK_EX)
  13687.                 return true;
  13688.             }
  13689.             $open_mode = 'w';
  13690.             // XXX People reported problems with LOCK_SH and 'w'
  13691.             if ($mode === LOCK_SH) {
  13692.                 if (!file_exists($this->_lockfile)) {
  13693.                     touch($this->_lockfile);
  13694.                 } elseif (!is_file($this->_lockfile)) {
  13695.                     return PEAR::raiseError('could not create Dependency lock file, ' .
  13696.                         'it exists and is not a regular file');
  13697.                 }
  13698.                 $open_mode = 'r';
  13699.             }
  13700.  
  13701.             if (!is_resource($this->_lockFp)) {
  13702.                 $this->_lockFp = @fopen($this->_lockfile, $open_mode);
  13703.             }
  13704.             if (!is_resource($this->_lockFp)) {
  13705.                 return PEAR::raiseError("could not create Dependency lock file" .
  13706.                                          (isset($php_errormsg) ? ": " . $php_errormsg : ""));
  13707.             }
  13708.             if (!(int)flock($this->_lockFp, $mode)) {
  13709.                 switch ($mode) {
  13710.                     case LOCK_SH: $str = 'shared';    break;
  13711.                     case LOCK_EX: $str = 'exclusive'; break;
  13712.                     case LOCK_UN: $str = 'unlock';    break;
  13713.                     default:      $str = 'unknown';   break;
  13714.                 }
  13715.                 return PEAR::raiseError("could not acquire $str lock ($this->_lockfile)");
  13716.             }
  13717.         }
  13718.         return true;
  13719.     }
  13720.  
  13721.     /**
  13722.      * Release usage of dependency DB
  13723.      * @return true|PEAR_Error
  13724.      * @access private
  13725.      */
  13726.     function _unlock()
  13727.     {
  13728.         $ret = $this->_lock(LOCK_UN);
  13729.         if (is_resource($this->_lockFp)) {
  13730.             fclose($this->_lockFp);
  13731.         }
  13732.         $this->_lockFp = null;
  13733.         return $ret;
  13734.     }
  13735.  
  13736.     /**
  13737.      * Load the dependency database from disk, or return the cache
  13738.      * @return array|PEAR_Error
  13739.      */
  13740.     function _getDepDB()
  13741.     {
  13742.         if (!$this->hasWriteAccess()) {
  13743.             return array('_version' => $this->_version);
  13744.         }
  13745.         if (isset($this->_cache)) {
  13746.             return $this->_cache;
  13747.         }
  13748.         if (!$fp = fopen($this->_depdb, 'r')) {
  13749.             $err = PEAR::raiseError("Could not open dependencies file `".$this->_depdb."'");
  13750.             return $err;
  13751.         }
  13752.         $rt = get_magic_quotes_runtime();
  13753.         set_magic_quotes_runtime(0);
  13754.         clearstatcache();
  13755.         fclose($fp);
  13756.         $data = unserialize(file_get_contents($this->_depdb));
  13757.         set_magic_quotes_runtime($rt);
  13758.         $this->_cache = $data;
  13759.         return $data;
  13760.     }
  13761.  
  13762.     /**
  13763.      * Write out the dependency database to disk
  13764.      * @param array the database
  13765.      * @return true|PEAR_Error
  13766.      * @access private
  13767.      */
  13768.     function _writeDepDB(&$deps)
  13769.     {
  13770.         if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
  13771.             return $e;
  13772.         }
  13773.         if (!$fp = fopen($this->_depdb, 'wb')) {
  13774.             $this->_unlock();
  13775.             return PEAR::raiseError("Could not open dependencies file `".$this->_depdb."' for writing");
  13776.         }
  13777.         $rt = get_magic_quotes_runtime();
  13778.         set_magic_quotes_runtime(0);
  13779.         fwrite($fp, serialize($deps));
  13780.         set_magic_quotes_runtime($rt);
  13781.         fclose($fp);
  13782.         $this->_unlock();
  13783.         $this->_cache = $deps;
  13784.         return true;
  13785.     }
  13786.  
  13787.     /**
  13788.      * Register all dependencies from a package in the dependencies database, in essence
  13789.      * "installing" the package's dependency information
  13790.      * @param array the database
  13791.      * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  13792.      * @access private
  13793.      */
  13794.     function _setPackageDeps(&$data, &$pkg)
  13795.     {
  13796.         $pkg->setConfig($this->_config);
  13797.         if ($pkg->getPackagexmlVersion() == '1.0') {
  13798.             $gen = &$pkg->getDefaultGenerator();
  13799.             $deps = $gen->dependenciesToV2();
  13800.         } else {
  13801.             $deps = $pkg->getDeps(true);
  13802.         }
  13803.         if (!$deps) {
  13804.             return;
  13805.         }
  13806.         if (!is_array($data)) {
  13807.             $data = array();
  13808.         }
  13809.         if (!isset($data['dependencies'])) {
  13810.             $data['dependencies'] = array();
  13811.         }
  13812.         if (!isset($data['dependencies'][strtolower($pkg->getChannel())])) {
  13813.             $data['dependencies'][strtolower($pkg->getChannel())] = array();
  13814.         }
  13815.         $data['dependencies'][strtolower($pkg->getChannel())][strtolower($pkg->getPackage())]
  13816.             = array();
  13817.         if (isset($deps['required']['package'])) {
  13818.             if (!isset($deps['required']['package'][0])) {
  13819.                 $deps['required']['package'] = array($deps['required']['package']);
  13820.             }
  13821.             foreach ($deps['required']['package'] as $dep) {
  13822.                 $this->_registerDep($data, $pkg, $dep, 'required');
  13823.             }
  13824.         }
  13825.         if (isset($deps['optional']['package'])) {
  13826.             if (!isset($deps['optional']['package'][0])) {
  13827.                 $deps['optional']['package'] = array($deps['optional']['package']);
  13828.             }
  13829.             foreach ($deps['optional']['package'] as $dep) {
  13830.                 $this->_registerDep($data, $pkg, $dep, 'optional');
  13831.             }
  13832.         }
  13833.         if (isset($deps['required']['subpackage'])) {
  13834.             if (!isset($deps['required']['subpackage'][0])) {
  13835.                 $deps['required']['subpackage'] = array($deps['required']['subpackage']);
  13836.             }
  13837.             foreach ($deps['required']['subpackage'] as $dep) {
  13838.                 $this->_registerDep($data, $pkg, $dep, 'required');
  13839.             }
  13840.         }
  13841.         if (isset($deps['optional']['subpackage'])) {
  13842.             if (!isset($deps['optional']['subpackage'][0])) {
  13843.                 $deps['optional']['subpackage'] = array($deps['optional']['subpackage']);
  13844.             }
  13845.             foreach ($deps['optional']['subpackage'] as $dep) {
  13846.                 $this->_registerDep($data, $pkg, $dep, 'optional');
  13847.             }
  13848.         }
  13849.         if (isset($deps['group'])) {
  13850.             if (!isset($deps['group'][0])) {
  13851.                 $deps['group'] = array($deps['group']);
  13852.             }
  13853.             foreach ($deps['group'] as $group) {
  13854.                 if (isset($group['package'])) {
  13855.                     if (!isset($group['package'][0])) {
  13856.                         $group['package'] = array($group['package']);
  13857.                     }
  13858.                     foreach ($group['package'] as $dep) {
  13859.                         $this->_registerDep($data, $pkg, $dep, 'optional',
  13860.                             $group['attribs']['name']);
  13861.                     }
  13862.                 }
  13863.                 if (isset($group['subpackage'])) {
  13864.                     if (!isset($group['subpackage'][0])) {
  13865.                         $group['subpackage'] = array($group['subpackage']);
  13866.                     }
  13867.                     foreach ($group['subpackage'] as $dep) {
  13868.                         $this->_registerDep($data, $pkg, $dep, 'optional',
  13869.                             $group['attribs']['name']);
  13870.                     }
  13871.                 }
  13872.             }
  13873.         }
  13874.         if ($data['dependencies'][strtolower($pkg->getChannel())]
  13875.               [strtolower($pkg->getPackage())] == array()) {
  13876.             unset($data['dependencies'][strtolower($pkg->getChannel())]
  13877.               [strtolower($pkg->getPackage())]);
  13878.             if (!count($data['dependencies'][strtolower($pkg->getChannel())])) {
  13879.                 unset($data['dependencies'][strtolower($pkg->getChannel())]);
  13880.             }
  13881.         }
  13882.     }
  13883.  
  13884.     /**
  13885.      * @param array the database
  13886.      * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  13887.      * @param array the specific dependency
  13888.      * @param required|optional whether this is a required or an optional dep
  13889.      * @param string|false dependency group this dependency is from, or false for ordinary dep
  13890.      */
  13891.     function _registerDep(&$data, &$pkg, $dep, $type, $group = false)
  13892.     {
  13893.         $info = array(
  13894.             'dep' => $dep,
  13895.             'type' => $type,
  13896.             'group' => $group);
  13897.  
  13898.         if (isset($dep['channel'])) {
  13899.             $depchannel = $dep['channel'];
  13900.         } else {
  13901.             $depchannel = '__uri';
  13902.         }
  13903.         if (!isset($data['dependencies'])) {
  13904.             $data['dependencies'] = array();
  13905.         }
  13906.         if (!isset($data['dependencies'][strtolower($pkg->getChannel())])) {
  13907.             $data['dependencies'][strtolower($pkg->getChannel())] = array();
  13908.         }
  13909.         if (!isset($data['dependencies'][strtolower($pkg->getChannel())][strtolower($pkg->getPackage())])) {
  13910.             $data['dependencies'][strtolower($pkg->getChannel())][strtolower($pkg->getPackage())] = array();
  13911.         }
  13912.         $data['dependencies'][strtolower($pkg->getChannel())][strtolower($pkg->getPackage())][]
  13913.             = $info;
  13914.         if (isset($data['packages'][strtolower($depchannel)][strtolower($dep['name'])])) {
  13915.             $found = false;
  13916.             foreach ($data['packages'][strtolower($depchannel)][strtolower($dep['name'])]
  13917.                   as $i => $p) {
  13918.                 if ($p['channel'] == strtolower($pkg->getChannel()) &&
  13919.                       $p['package'] == strtolower($pkg->getPackage())) {
  13920.                     $found = true;
  13921.                     break;
  13922.                 }
  13923.             }
  13924.             if (!$found) {
  13925.                 $data['packages'][strtolower($depchannel)][strtolower($dep['name'])][]
  13926.                     = array('channel' => strtolower($pkg->getChannel()),
  13927.                             'package' => strtolower($pkg->getPackage()));
  13928.             }
  13929.         } else {
  13930.             if (!isset($data['packages'])) {
  13931.                 $data['packages'] = array();
  13932.             }
  13933.             if (!isset($data['packages'][strtolower($depchannel)])) {
  13934.                 $data['packages'][strtolower($depchannel)] = array();
  13935.             }
  13936.             if (!isset($data['packages'][strtolower($depchannel)][strtolower($dep['name'])])) {
  13937.                 $data['packages'][strtolower($depchannel)][strtolower($dep['name'])] = array();
  13938.             }
  13939.             $data['packages'][strtolower($depchannel)][strtolower($dep['name'])][]
  13940.                 = array('channel' => strtolower($pkg->getChannel()),
  13941.                         'package' => strtolower($pkg->getPackage()));
  13942.         }
  13943.     }
  13944. }
  13945. ?><?php
  13946. /**
  13947.  * PEAR_Downloader, the PEAR Installer's download utility class
  13948.  *
  13949.  * PHP versions 4 and 5
  13950.  *
  13951.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  13952.  * that is available through the world-wide-web at the following URI:
  13953.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  13954.  * the PHP License and are unable to obtain it through the web, please
  13955.  * send a note to license@php.net so we can mail you a copy immediately.
  13956.  *
  13957.  * @category   pear
  13958.  * @package    PEAR
  13959.  * @author     Greg Beaver <cellog@php.net>
  13960.  * @author     Stig Bakken <ssb@php.net>
  13961.  * @author     Tomas V. V. Cox <cox@idecnet.com>
  13962.  * @author     Martin Jansen <mj@php.net>
  13963.  * @copyright  1997-2008 The PHP Group
  13964.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  13965.  * @version    CVS: $Id: Downloader.php,v 1.137 2008/01/29 03:21:01 cellog Exp $
  13966.  * @link       http://pear.php.net/package/PEAR
  13967.  * @since      File available since Release 1.3.0
  13968.  */
  13969.  
  13970. /**
  13971.  * Needed for constants, extending
  13972.  */
  13973. require_once 'phar://go-pear.phar/' . 'PEAR/Common.php';
  13974.  
  13975. define('PEAR_INSTALLER_OK',       1);
  13976. define('PEAR_INSTALLER_FAILED',   0);
  13977. define('PEAR_INSTALLER_SKIPPED', -1);
  13978. define('PEAR_INSTALLER_ERROR_NO_PREF_STATE', 2);
  13979.  
  13980. /**
  13981.  * Administration class used to download anything from the internet (PEAR Packages,
  13982.  * static URLs, xml files)
  13983.  *
  13984.  * @category   pear
  13985.  * @package    PEAR
  13986.  * @author     Greg Beaver <cellog@php.net>
  13987.  * @author     Stig Bakken <ssb@php.net>
  13988.  * @author     Tomas V. V. Cox <cox@idecnet.com>
  13989.  * @author     Martin Jansen <mj@php.net>
  13990.  * @copyright  1997-2008 The PHP Group
  13991.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  13992.  * @version    Release: 1.7.1
  13993.  * @link       http://pear.php.net/package/PEAR
  13994.  * @since      Class available since Release 1.3.0
  13995.  */
  13996. class PEAR_Downloader extends PEAR_Common
  13997. {
  13998.     /**
  13999.      * @var PEAR_Registry
  14000.      * @access private
  14001.      */
  14002.     var $_registry;
  14003.  
  14004.     /**
  14005.      * @var PEAR_Remote
  14006.      * @access private
  14007.      */
  14008.     var $_remote;
  14009.  
  14010.     /**
  14011.      * Preferred Installation State (snapshot, devel, alpha, beta, stable)
  14012.      * @var string|null
  14013.      * @access private
  14014.      */
  14015.     var $_preferredState;
  14016.  
  14017.     /**
  14018.      * Options from command-line passed to Install.
  14019.      *
  14020.      * Recognized options:<br />
  14021.      *  - onlyreqdeps   : install all required dependencies as well
  14022.      *  - alldeps       : install all dependencies, including optional
  14023.      *  - installroot   : base relative path to install files in
  14024.      *  - force         : force a download even if warnings would prevent it
  14025.      *  - nocompress    : download uncompressed tarballs
  14026.      * @see PEAR_Command_Install
  14027.      * @access private
  14028.      * @var array
  14029.      */
  14030.     var $_options;
  14031.  
  14032.     /**
  14033.      * Downloaded Packages after a call to download().
  14034.      *
  14035.      * Format of each entry:
  14036.      *
  14037.      * <code>
  14038.      * array('pkg' => 'package_name', 'file' => '/path/to/local/file',
  14039.      *    'info' => array() // parsed package.xml
  14040.      * );
  14041.      * </code>
  14042.      * @access private
  14043.      * @var array
  14044.      */
  14045.     var $_downloadedPackages = array();
  14046.  
  14047.     /**
  14048.      * Packages slated for download.
  14049.      *
  14050.      * This is used to prevent downloading a package more than once should it be a dependency
  14051.      * for two packages to be installed.
  14052.      * Format of each entry:
  14053.      *
  14054.      * <pre>
  14055.      * array('package_name1' => parsed package.xml, 'package_name2' => parsed package.xml,
  14056.      * );
  14057.      * </pre>
  14058.      * @access private
  14059.      * @var array
  14060.      */
  14061.     var $_toDownload = array();
  14062.  
  14063.     /**
  14064.      * Array of every package installed, with names lower-cased.
  14065.      *
  14066.      * Format:
  14067.      * <code>
  14068.      * array('package1' => 0, 'package2' => 1, );
  14069.      * </code>
  14070.      * @var array
  14071.      */
  14072.     var $_installed = array();
  14073.  
  14074.     /**
  14075.      * @var array
  14076.      * @access private
  14077.      */
  14078.     var $_errorStack = array();
  14079.     
  14080.     /**
  14081.      * @var boolean
  14082.      * @access private
  14083.      */
  14084.     var $_internalDownload = false;
  14085.  
  14086.     /**
  14087.      * Temporary variable used in sorting packages by dependency in {@link sortPkgDeps()}
  14088.      * @var array
  14089.      * @access private
  14090.      */
  14091.     var $_packageSortTree;
  14092.  
  14093.     /**
  14094.      * Temporary directory, or configuration value where downloads will occur
  14095.      * @var string
  14096.      */
  14097.     var $_downloadDir;
  14098.     // {{{ PEAR_Downloader()
  14099.  
  14100.     /**
  14101.      * @param PEAR_Frontend_*
  14102.      * @param array
  14103.      * @param PEAR_Config
  14104.      */
  14105.     function PEAR_Downloader(&$ui, $options, &$config)
  14106.     {
  14107.         parent::PEAR_Common();
  14108.         $this->_options = $options;
  14109.         $this->config = &$config;
  14110.         $this->_preferredState = $this->config->get('preferred_state');
  14111.         $this->ui = &$ui;
  14112.         if (!$this->_preferredState) {
  14113.             // don't inadvertantly use a non-set preferred_state
  14114.             $this->_preferredState = null;
  14115.         }
  14116.  
  14117.         if (isset($this->_options['installroot'])) {
  14118.             $this->config->setInstallRoot($this->_options['installroot']);
  14119.         }
  14120.         $this->_registry = &$config->getRegistry();
  14121.         $this->_remote = &$config->getRemote();
  14122.  
  14123.         if (isset($this->_options['alldeps']) || isset($this->_options['onlyreqdeps'])) {
  14124.             $this->_installed = $this->_registry->listAllPackages();
  14125.             foreach ($this->_installed as $key => $unused) {
  14126.                 if (!count($unused)) {
  14127.                     continue;
  14128.                 }
  14129.                 $strtolower = create_function('$a','return strtolower($a);');
  14130.                 array_walk($this->_installed[$key], $strtolower);
  14131.             }
  14132.         }
  14133.     }
  14134.  
  14135.     /**
  14136.      * Attempt to discover a channel's remote capabilities from
  14137.      * its server name
  14138.      * @param string
  14139.      * @return boolean
  14140.      */
  14141.     function discover($channel)
  14142.     {
  14143.         $this->log(1, 'Attempting to discover channel "' . $channel . '"...');
  14144.         PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  14145.         $callback = $this->ui ? array(&$this, '_downloadCallback') : null;
  14146.         if (!class_exists('System')) {
  14147.             require_once 'phar://go-pear.phar/' . 'System.php';
  14148.         }
  14149.         $a = $this->downloadHttp('http://' . $channel . '/channel.xml', $this->ui,
  14150.             System::mktemp(array('-d')), $callback, false);
  14151.         PEAR::popErrorHandling();
  14152.         if (PEAR::isError($a)) {
  14153.             return false;
  14154.         }
  14155.         list($a, $lastmodified) = $a;
  14156.         if (!class_exists('PEAR_ChannelFile')) {
  14157.             require_once 'phar://go-pear.phar/' . 'PEAR/ChannelFile.php';
  14158.         }
  14159.         $b = new PEAR_ChannelFile;
  14160.         if ($b->fromXmlFile($a)) {
  14161.             unlink($a);
  14162.             if ($this->config->get('auto_discover')) {
  14163.                 $this->_registry->addChannel($b, $lastmodified);
  14164.                 $alias = $b->getName();
  14165.                 if ($b->getName() == $this->_registry->channelName($b->getAlias())) {
  14166.                     $alias = $b->getAlias();
  14167.                 }
  14168.                 $this->log(1, 'Auto-discovered channel "' . $channel .
  14169.                     '", alias "' . $alias . '", adding to registry');
  14170.             }
  14171.             return true;
  14172.         }
  14173.         unlink($a);
  14174.         return false;
  14175.     }
  14176.  
  14177.     /**
  14178.      * For simpler unit-testing
  14179.      * @param PEAR_Downloader
  14180.      * @return PEAR_Downloader_Package
  14181.      */
  14182.     function &newDownloaderPackage(&$t)
  14183.     {
  14184.         if (!class_exists('PEAR_Downloader_Package')) {
  14185.             require_once 'phar://go-pear.phar/' . 'PEAR/Downloader/Package.php';
  14186.         }
  14187.         $a = &new PEAR_Downloader_Package($t);
  14188.         return $a;
  14189.     }
  14190.  
  14191.     /**
  14192.      * For simpler unit-testing
  14193.      * @param PEAR_Config
  14194.      * @param array
  14195.      * @param array
  14196.      * @param int
  14197.      */
  14198.     function &getDependency2Object(&$c, $i, $p, $s)
  14199.     {
  14200.         if (!class_exists('PEAR_Dependency2')) {
  14201.             require_once 'phar://go-pear.phar/' . 'PEAR/Dependency2.php';
  14202.         }
  14203.         $z = &new PEAR_Dependency2($c, $i, $p, $s);
  14204.         return $z;
  14205.     }
  14206.  
  14207.     function &download($params)
  14208.     {
  14209.         if (!count($params)) {
  14210.             $a = array();
  14211.             return $a;
  14212.         }
  14213.         if (!isset($this->_registry)) {
  14214.             $this->_registry = &$this->config->getRegistry();
  14215.         }
  14216.         if (!isset($this->_remote)) {
  14217.             $this->_remote = &$this->config->getRemote();
  14218.         }
  14219.         $channelschecked = array();
  14220.         // convert all parameters into PEAR_Downloader_Package objects
  14221.         foreach ($params as $i => $param) {
  14222.             $params[$i] = &$this->newDownloaderPackage($this);
  14223.             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  14224.             $err = $params[$i]->initialize($param);
  14225.             PEAR::staticPopErrorHandling();
  14226.             if (!$err) {
  14227.                 // skip parameters that were missed by preferred_state
  14228.                 continue;
  14229.             }
  14230.             if (PEAR::isError($err)) {
  14231.                 if (!isset($this->_options['soft'])) {
  14232.                     $this->log(0, $err->getMessage());
  14233.                 }
  14234.                 $params[$i] = false;
  14235.                 if (is_object($param)) {
  14236.                     $param = $param->getChannel() . '/' . $param->getPackage();
  14237.                 }
  14238.                 $this->pushError('Package "' . $param . '" is not valid',
  14239.                     PEAR_INSTALLER_SKIPPED);
  14240.             } else {
  14241.                 do {
  14242.                     if ($params[$i] && $params[$i]->getType() == 'local') {
  14243.                         // bug #7090
  14244.                         // skip channel.xml check for local packages
  14245.                         break;
  14246.                     }
  14247.                     if ($params[$i] && !isset($channelschecked[$params[$i]->getChannel()]) &&
  14248.                           !isset($this->_options['offline'])) {
  14249.                         $channelschecked[$params[$i]->getChannel()] = true;
  14250.                         PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  14251.                         if (!class_exists('System')) {
  14252.                             require_once 'phar://go-pear.phar/' . 'System.php';
  14253.                         }
  14254.                         $curchannel = &$this->_registry->getChannel($params[$i]->getChannel());
  14255.                         if (PEAR::isError($curchannel)) {
  14256.                             PEAR::staticPopErrorHandling();
  14257.                             return $this->raiseError($curchannel);
  14258.                         }
  14259.                         if (PEAR::isError($dir = $this->getDownloadDir())) {
  14260.                             PEAR::staticPopErrorHandling();
  14261.                             break;
  14262.                         }
  14263.                         $mirror = $this->config->get('preferred_mirror', null,
  14264.                                                      $params[$i]->getChannel());
  14265.                         $a = $this->downloadHttp('http://' . $mirror .
  14266.                             '/channel.xml', $this->ui, $dir, null, $curchannel->lastModified());
  14267.  
  14268.                         PEAR::staticPopErrorHandling();
  14269.                         if (PEAR::isError($a) || !$a) {
  14270.                             break;
  14271.                         }
  14272.                         $this->log(0, 'WARNING: channel "' . $params[$i]->getChannel() . '" has ' .
  14273.                             'updated its protocols, use "channel-update ' . $params[$i]->getChannel() .
  14274.                             '" to update');
  14275.                     }
  14276.                 } while (false);
  14277.                 if ($params[$i] && !isset($this->_options['downloadonly'])) {
  14278.                     if (isset($this->_options['packagingroot'])) {
  14279.                         $checkdir = $this->_prependPath(
  14280.                             $this->config->get('php_dir', null, $params[$i]->getChannel()),
  14281.                             $this->_options['packagingroot']);
  14282.                     } else {
  14283.                         $checkdir = $this->config->get('php_dir',
  14284.                             null, $params[$i]->getChannel());
  14285.                     }
  14286.                     while ($checkdir && $checkdir != '/' && !file_exists($checkdir)) {
  14287.                         $checkdir = dirname($checkdir);
  14288.                     }
  14289.                     if ($checkdir == '.') {
  14290.                         $checkdir = '/';
  14291.                     }
  14292.                     if (!is_writeable($checkdir)) {
  14293.                         return PEAR::raiseError('Cannot install, php_dir for channel "' .
  14294.                             $params[$i]->getChannel() . '" is not writeable by the current user');
  14295.                     }
  14296.                 }
  14297.             }
  14298.         }
  14299.         unset($channelschecked);
  14300.         PEAR_Downloader_Package::removeDuplicates($params);
  14301.         if (!count($params)) {
  14302.             $a = array();
  14303.             return $a;
  14304.         }
  14305.         if (!isset($this->_options['nodeps']) && !isset($this->_options['offline'])) {
  14306.             $reverify = true;
  14307.             while ($reverify) {
  14308.                 $reverify = false;
  14309.                 foreach ($params as $i => $param) {
  14310.                     //PHP Bug 40768 / PEAR Bug #10944
  14311.                     //Nested foreaches fail in PHP 5.2.1
  14312.                     key($params);
  14313.                     $ret = $params[$i]->detectDependencies($params);
  14314.                     if (PEAR::isError($ret)) {
  14315.                         $reverify = true;
  14316.                         $params[$i] = false;
  14317.                         PEAR_Downloader_Package::removeDuplicates($params);
  14318.                         if (!isset($this->_options['soft'])) {
  14319.                             $this->log(0, $ret->getMessage());
  14320.                         }
  14321.                         continue 2;
  14322.                     }
  14323.                 }
  14324.             }
  14325.         }
  14326.         if (isset($this->_options['offline'])) {
  14327.             $this->log(3, 'Skipping dependency download check, --offline specified');
  14328.         }
  14329.         if (!count($params)) {
  14330.             $a = array();
  14331.             return $a;
  14332.         }
  14333.         while (PEAR_Downloader_Package::mergeDependencies($params));
  14334.         PEAR_Downloader_Package::removeDuplicates($params, true);
  14335.         $errorparams = array();
  14336.         if (PEAR_Downloader_Package::detectStupidDuplicates($params, $errorparams)) {
  14337.             if (count($errorparams)) {
  14338.                 foreach ($errorparams as $param) {
  14339.                     $name = $this->_registry->parsedPackageNameToString($param->getParsedPackage());
  14340.                     $this->pushError('Duplicate package ' . $name . ' found', PEAR_INSTALLER_FAILED);
  14341.                 }
  14342.                 $a = array();
  14343.                 return $a;
  14344.             }
  14345.         }
  14346.         PEAR_Downloader_Package::removeInstalled($params);
  14347.         if (!count($params)) {
  14348.             $this->pushError('No valid packages found', PEAR_INSTALLER_FAILED);
  14349.             $a = array();
  14350.             return $a;
  14351.         }
  14352.         PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  14353.         $err = $this->analyzeDependencies($params);
  14354.         PEAR::popErrorHandling();
  14355.         if (!count($params)) {
  14356.             $this->pushError('No valid packages found', PEAR_INSTALLER_FAILED);
  14357.             $a = array();
  14358.             return $a;
  14359.         }
  14360.         $ret = array();
  14361.         $newparams = array();
  14362.         if (isset($this->_options['pretend'])) {
  14363.             return $params;
  14364.         }
  14365.         $somefailed = false;
  14366.         foreach ($params as $i => $package) {
  14367.             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  14368.             $pf = &$params[$i]->download();
  14369.             PEAR::staticPopErrorHandling();
  14370.             if (PEAR::isError($pf)) {
  14371.                 if (!isset($this->_options['soft'])) {
  14372.                     $this->log(1, $pf->getMessage());
  14373.                     $this->log(0, 'Error: cannot download "' .
  14374.                         $this->_registry->parsedPackageNameToString($package->getParsedPackage(),
  14375.                             true) .
  14376.                         '"');
  14377.                 }
  14378.                 $somefailed = true;
  14379.                 continue;
  14380.             }
  14381.             $newparams[] = &$params[$i];
  14382.             $ret[] = array('file' => $pf->getArchiveFile(),
  14383.                                    'info' => &$pf,
  14384.                                    'pkg' => $pf->getPackage());
  14385.         }
  14386.         if ($somefailed) {
  14387.             // remove params that did not download successfully
  14388.             PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  14389.             $err = $this->analyzeDependencies($newparams, true);
  14390.             PEAR::popErrorHandling();
  14391.             if (!count($newparams)) {
  14392.                 $this->pushError('Download failed', PEAR_INSTALLER_FAILED);
  14393.                 $a = array();
  14394.                 return $a;
  14395.             }
  14396.         }
  14397.         $this->_downloadedPackages = $ret;
  14398.         return $newparams;
  14399.     }
  14400.  
  14401.     /**
  14402.      * @param array all packages to be installed
  14403.      */
  14404.     function analyzeDependencies(&$params, $force = false)
  14405.     {
  14406.         $hasfailed = $failed = false;
  14407.         if (isset($this->_options['downloadonly'])) {
  14408.             return;
  14409.         }
  14410.         PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  14411.         $redo = true;
  14412.         $reset = false;
  14413.         while ($redo) {
  14414.             $redo = false;
  14415.             foreach ($params as $i => $param) {
  14416.                 $deps = $param->getDeps();
  14417.                 if (!$deps) {
  14418.                     $depchecker = &$this->getDependency2Object($this->config, $this->getOptions(),
  14419.                         $param->getParsedPackage(), PEAR_VALIDATE_DOWNLOADING);
  14420.                     if ($param->getType() == 'xmlrpc') {
  14421.                         $send = $param->getDownloadURL();
  14422.                     } else {
  14423.                         $send = $param->getPackageFile();
  14424.                     }
  14425.                     $installcheck = $depchecker->validatePackage($send, $this, $params);
  14426.                     if (PEAR::isError($installcheck)) {
  14427.                         if (!isset($this->_options['soft'])) {
  14428.                             $this->log(0, $installcheck->getMessage());
  14429.                         }
  14430.                         $hasfailed = true;
  14431.                         $params[$i] = false;
  14432.                         $reset = true;
  14433.                         $redo = true;
  14434.                         $failed = false;
  14435.                         PEAR_Downloader_Package::removeDuplicates($params);
  14436.                         continue 2;
  14437.                     }
  14438.                     continue;
  14439.                 }
  14440.                 if (!$reset && $param->alreadyValidated() && !$force) {
  14441.                     continue;
  14442.                 }
  14443.                 if (count($deps)) {
  14444.                     $depchecker = &$this->getDependency2Object($this->config, $this->getOptions(),
  14445.                         $param->getParsedPackage(), PEAR_VALIDATE_DOWNLOADING);
  14446.                     if ($param->getType() == 'xmlrpc') {
  14447.                         $send = $param->getDownloadURL();
  14448.                     } else {
  14449.                         $send = $param->getPackageFile();
  14450.                     }
  14451.                     $installcheck = $depchecker->validatePackage($send, $this, $params);
  14452.                     if (PEAR::isError($installcheck)) {
  14453.                         if (!isset($this->_options['soft'])) {
  14454.                             $this->log(0, $installcheck->getMessage());
  14455.                         }
  14456.                         $hasfailed = true;
  14457.                         $params[$i] = false;
  14458.                         $reset = true;
  14459.                         $redo = true;
  14460.                         $failed = false;
  14461.                         PEAR_Downloader_Package::removeDuplicates($params);
  14462.                         continue 2;
  14463.                     }
  14464.                     $failed = false;
  14465.                     if (isset($deps['required'])) {
  14466.                         foreach ($deps['required'] as $type => $dep) {
  14467.                             // note: Dependency2 will never return a PEAR_Error if ignore-errors
  14468.                             // is specified, so soft is needed to turn off logging
  14469.                             if (!isset($dep[0])) {
  14470.                                 if (PEAR::isError($e = $depchecker->{"validate{$type}Dependency"}($dep,
  14471.                                       true, $params))) {
  14472.                                     $failed = true;
  14473.                                     if (!isset($this->_options['soft'])) {
  14474.                                         $this->log(0, $e->getMessage());
  14475.                                     }
  14476.                                 } elseif (is_array($e) && !$param->alreadyValidated()) {
  14477.                                     if (!isset($this->_options['soft'])) {
  14478.                                         $this->log(0, $e[0]);
  14479.                                     }
  14480.                                 }
  14481.                             } else {
  14482.                                 foreach ($dep as $d) {
  14483.                                     if (PEAR::isError($e =
  14484.                                           $depchecker->{"validate{$type}Dependency"}($d,
  14485.                                           true, $params))) {
  14486.                                         $failed = true;
  14487.                                         if (!isset($this->_options['soft'])) {
  14488.                                             $this->log(0, $e->getMessage());
  14489.                                         }
  14490.                                     } elseif (is_array($e) && !$param->alreadyValidated()) {
  14491.                                         if (!isset($this->_options['soft'])) {
  14492.                                             $this->log(0, $e[0]);
  14493.                                         }
  14494.                                     }
  14495.                                 }
  14496.                             }
  14497.                         }
  14498.                         if (isset($deps['optional'])) {
  14499.                             foreach ($deps['optional'] as $type => $dep) {
  14500.                                 if (!isset($dep[0])) {
  14501.                                     if (PEAR::isError($e =
  14502.                                           $depchecker->{"validate{$type}Dependency"}($dep,
  14503.                                           false, $params))) {
  14504.                                         $failed = true;
  14505.                                         if (!isset($this->_options['soft'])) {
  14506.                                             $this->log(0, $e->getMessage());
  14507.                                         }
  14508.                                     } elseif (is_array($e) && !$param->alreadyValidated()) {
  14509.                                         if (!isset($this->_options['soft'])) {
  14510.                                             $this->log(0, $e[0]);
  14511.                                         }
  14512.                                     }
  14513.                                 } else {
  14514.                                     foreach ($dep as $d) {
  14515.                                         if (PEAR::isError($e =
  14516.                                               $depchecker->{"validate{$type}Dependency"}($d,
  14517.                                               false, $params))) {
  14518.                                             $failed = true;
  14519.                                             if (!isset($this->_options['soft'])) {
  14520.                                                 $this->log(0, $e->getMessage());
  14521.                                             }
  14522.                                         } elseif (is_array($e) && !$param->alreadyValidated()) {
  14523.                                             if (!isset($this->_options['soft'])) {
  14524.                                                 $this->log(0, $e[0]);
  14525.                                             }
  14526.                                         }
  14527.                                     }
  14528.                                 }
  14529.                             }
  14530.                         }
  14531.                         $groupname = $param->getGroup();
  14532.                         if (isset($deps['group']) && $groupname) {
  14533.                             if (!isset($deps['group'][0])) {
  14534.                                 $deps['group'] = array($deps['group']);
  14535.                             }
  14536.                             $found = false;
  14537.                             foreach ($deps['group'] as $group) {
  14538.                                 if ($group['attribs']['name'] == $groupname) {
  14539.                                     $found = true;
  14540.                                     break;
  14541.                                 }
  14542.                             }
  14543.                             if ($found) {
  14544.                                 unset($group['attribs']);
  14545.                                 foreach ($group as $type => $dep) {
  14546.                                     if (!isset($dep[0])) {
  14547.                                         if (PEAR::isError($e =
  14548.                                               $depchecker->{"validate{$type}Dependency"}($dep,
  14549.                                               false, $params))) {
  14550.                                             $failed = true;
  14551.                                             if (!isset($this->_options['soft'])) {
  14552.                                                 $this->log(0, $e->getMessage());
  14553.                                             }
  14554.                                         } elseif (is_array($e) && !$param->alreadyValidated()) {
  14555.                                             if (!isset($this->_options['soft'])) {
  14556.                                                 $this->log(0, $e[0]);
  14557.                                             }
  14558.                                         }
  14559.                                     } else {
  14560.                                         foreach ($dep as $d) {
  14561.                                             if (PEAR::isError($e =
  14562.                                                   $depchecker->{"validate{$type}Dependency"}($d,
  14563.                                                   false, $params))) {
  14564.                                                 $failed = true;
  14565.                                                 if (!isset($this->_options['soft'])) {
  14566.                                                     $this->log(0, $e->getMessage());
  14567.                                                 }
  14568.                                             } elseif (is_array($e) && !$param->alreadyValidated()) {
  14569.                                                 if (!isset($this->_options['soft'])) {
  14570.                                                     $this->log(0, $e[0]);
  14571.                                                 }
  14572.                                             }
  14573.                                         }
  14574.                                     }
  14575.                                 }
  14576.                             }
  14577.                         }
  14578.                     } else {
  14579.                         foreach ($deps as $dep) {
  14580.                             if (PEAR::isError($e = $depchecker->validateDependency1($dep, $params))) {
  14581.                                 $failed = true;
  14582.                                 if (!isset($this->_options['soft'])) {
  14583.                                     $this->log(0, $e->getMessage());
  14584.                                 }
  14585.                             } elseif (is_array($e) && !$param->alreadyValidated()) {
  14586.                                 if (!isset($this->_options['soft'])) {
  14587.                                     $this->log(0, $e[0]);
  14588.                                 }
  14589.                             }
  14590.                         }
  14591.                     }
  14592.                     $params[$i]->setValidated();
  14593.                 }
  14594.                 if ($failed) {
  14595.                     $hasfailed = true;
  14596.                     $params[$i] = false;
  14597.                     $reset = true;
  14598.                     $redo = true;
  14599.                     $failed = false;
  14600.                     PEAR_Downloader_Package::removeDuplicates($params);
  14601.                     continue 2;
  14602.                 }
  14603.             }
  14604.         }
  14605.         PEAR::staticPopErrorHandling();
  14606.         if ($hasfailed && (isset($this->_options['ignore-errors']) ||
  14607.               isset($this->_options['nodeps']))) {
  14608.             // this is probably not needed, but just in case
  14609.             if (!isset($this->_options['soft'])) {
  14610.                 $this->log(0, 'WARNING: dependencies failed');
  14611.             }
  14612.         }
  14613.     }
  14614.  
  14615.     /**
  14616.      * Retrieve the directory that downloads will happen in
  14617.      * @access private
  14618.      * @return string
  14619.      */
  14620.     function getDownloadDir()
  14621.     {
  14622.         if (isset($this->_downloadDir)) {
  14623.             return $this->_downloadDir;
  14624.         }
  14625.         $downloaddir = $this->config->get('download_dir');
  14626.         if (empty($downloaddir) || (is_dir($downloaddir) && !is_writable($downloaddir))) {
  14627.             if  (is_dir($downloaddir) && !is_writable($downloaddir)) {
  14628.                 $this->log(0, 'WARNING: configuration download directory "' . $downloaddir .
  14629.                     '" is not writeable.  Change download_dir config variable to ' .
  14630.                     'a writeable dir to avoid this warning');
  14631.             }
  14632.             if (!class_exists('System')) {
  14633.                 require_once 'phar://go-pear.phar/' . 'System.php';
  14634.             }
  14635.             if (PEAR::isError($downloaddir = System::mktemp('-d'))) {
  14636.                 return $downloaddir;
  14637.             }
  14638.             $this->log(3, '+ tmp dir created at ' . $downloaddir);
  14639.         }
  14640.         if (!is_writable($downloaddir)) {
  14641.             if (PEAR::isError(System::mkdir(array('-p', $downloaddir))) ||
  14642.                   !is_writable($downloaddir)) {
  14643.                 return PEAR::raiseError('download directory "' . $downloaddir .
  14644.                     '" is not writeable.  Change download_dir config variable to ' .
  14645.                     'a writeable dir');
  14646.             }
  14647.         }
  14648.         return $this->_downloadDir = $downloaddir;
  14649.     }
  14650.  
  14651.     function setDownloadDir($dir)
  14652.     {
  14653.         if (!@is_writable($dir)) {
  14654.             if (PEAR::isError(System::mkdir(array('-p', $dir)))) {
  14655.                 return PEAR::raiseError('download directory "' . $dir .
  14656.                     '" is not writeable.  Change download_dir config variable to ' .
  14657.                     'a writeable dir');
  14658.             }
  14659.         }
  14660.         $this->_downloadDir = $dir;
  14661.     }
  14662.  
  14663.     // }}}
  14664.     // {{{ configSet()
  14665.     function configSet($key, $value, $layer = 'user', $channel = false)
  14666.     {
  14667.         $this->config->set($key, $value, $layer, $channel);
  14668.         $this->_preferredState = $this->config->get('preferred_state', null, $channel);
  14669.         if (!$this->_preferredState) {
  14670.             // don't inadvertantly use a non-set preferred_state
  14671.             $this->_preferredState = null;
  14672.         }
  14673.     }
  14674.  
  14675.     // }}}
  14676.     // {{{ setOptions()
  14677.     function setOptions($options)
  14678.     {
  14679.         $this->_options = $options;
  14680.     }
  14681.  
  14682.     // }}}
  14683.     // {{{ setOptions()
  14684.     function getOptions()
  14685.     {
  14686.         return $this->_options;
  14687.     }
  14688.  
  14689.     // }}}
  14690.  
  14691.     /**
  14692.      * For simpler unit-testing
  14693.      * @param PEAR_Config
  14694.      * @param int
  14695.      * @param string
  14696.      */
  14697.     function &getPackagefileObject(&$c, $d, $t = false)
  14698.     {
  14699.         if (!class_exists('PEAR_PackageFile')) {
  14700.             require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile.php';
  14701.         }
  14702.         $a = &new PEAR_PackageFile($c, $d, $t);
  14703.         return $a;
  14704.     }
  14705.  
  14706.     // {{{ _getPackageDownloadUrl()
  14707.  
  14708.     /**
  14709.      * @param array output of {@link parsePackageName()}
  14710.      * @access private
  14711.      */
  14712.     function _getPackageDownloadUrl($parr)
  14713.     {
  14714.         $curchannel = $this->config->get('default_channel');
  14715.         $this->configSet('default_channel', $parr['channel']);
  14716.         // getDownloadURL returns an array.  On error, it only contains information
  14717.         // on the latest release as array(version, info).  On success it contains
  14718.         // array(version, info, download url string)
  14719.         $state = isset($parr['state']) ? $parr['state'] : $this->config->get('preferred_state');
  14720.         if (!$this->_registry->channelExists($parr['channel'])) {
  14721.             do {
  14722.                 if ($this->config->get('auto_discover')) {
  14723.                     if ($this->discover($parr['channel'])) {
  14724.                         break;
  14725.                     }
  14726.                 }
  14727.                 $this->configSet('default_channel', $curchannel);
  14728.                 return PEAR::raiseError('Unknown remote channel: ' . $remotechannel);
  14729.             } while (false);
  14730.         }
  14731.         $chan = &$this->_registry->getChannel($parr['channel']);
  14732.         if (PEAR::isError($chan)) {
  14733.             return $chan;
  14734.         }
  14735.         PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  14736.         $version = $this->_registry->packageInfo($parr['package'], 'version',
  14737.             $parr['channel']);
  14738.         PEAR::staticPopErrorHandling();
  14739.         $base2 = false;
  14740.         if ($chan->supportsREST($this->config->get('preferred_mirror')) &&
  14741.               (($base2 = $chan->getBaseURL('REST1.3', $this->config->get('preferred_mirror'))) ||
  14742.               ($base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))))) {
  14743.             if ($base2) {
  14744.                 $rest = &$this->config->getREST('1.3', $this->_options);
  14745.                 $base = $base2;
  14746.             } else {
  14747.                 $rest = &$this->config->getREST('1.0', $this->_options);
  14748.             }
  14749.             if (!isset($parr['version']) && !isset($parr['state']) && $version
  14750.                   && !PEAR::isError($version)
  14751.                   && !isset($this->_options['downloadonly'])) {
  14752.                 $url = $rest->getDownloadURL($base, $parr, $state, $version);
  14753.             } else {
  14754.                 $url = $rest->getDownloadURL($base, $parr, $state, false);
  14755.             }
  14756.             if (PEAR::isError($url)) {
  14757.                 $this->configSet('default_channel', $curchannel);
  14758.                 return $url;
  14759.             }
  14760.             if ($parr['channel'] != $curchannel) {
  14761.                 $this->configSet('default_channel', $curchannel);
  14762.             }
  14763.             if (!is_array($url)) {
  14764.                 return $url;
  14765.             }
  14766.             $url['raw'] = false; // no checking is necessary for REST
  14767.             if (!is_array($url['info'])) {
  14768.                 return PEAR::raiseError('Invalid remote dependencies retrieved from REST - ' .
  14769.                     'this should never happen');
  14770.             }
  14771.             if (!isset($this->_options['force']) &&
  14772.                   !isset($this->_options['downloadonly']) &&
  14773.                   $version &&
  14774.                   !PEAR::isError($version) &&
  14775.                   !isset($parr['group'])) {
  14776.                 if (version_compare($version, $url['version'], '>=')) {
  14777.                     return PEAR::raiseError($this->_registry->parsedPackageNameToString(
  14778.                         $parr, true) . ' is already installed and is newer than detected ' .
  14779.                         'release version ' . $url['version'], -976);
  14780.                 }
  14781.             }
  14782.             if (isset($url['info']['required']) || $url['compatible']) {
  14783.                 require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v2.php';
  14784.                 $pf = new PEAR_PackageFile_v2;
  14785.                 $pf->setRawChannel($parr['channel']);
  14786.                 if ($url['compatible']) {
  14787.                     $pf->setRawCompatible($url['compatible']);
  14788.                 }
  14789.             } else {
  14790.                 require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v1.php';
  14791.                 $pf = new PEAR_PackageFile_v1;
  14792.             }
  14793.             $pf->setRawPackage($url['package']);
  14794.             $pf->setDeps($url['info']);
  14795.             if ($url['compatible']) {
  14796.                 $pf->setCompatible($url['compatible']);
  14797.             }
  14798.             $pf->setRawState($url['stability']);
  14799.             $url['info'] = &$pf;
  14800.             if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) {
  14801.                 $ext = '.tar';
  14802.             } else {
  14803.                 $ext = '.tgz';
  14804.             }
  14805.             if (is_array($url)) {
  14806.                 if (isset($url['url'])) {
  14807.                     $url['url'] .= $ext;
  14808.                 }
  14809.             }
  14810.             return $url;
  14811.         } elseif ($chan->supports('xmlrpc', 'package.getDownloadURL', false, '1.1')) {
  14812.             // don't install with the old version information unless we're doing a plain
  14813.             // vanilla simple installation.  If the user says to install a particular
  14814.             // version or state, ignore the current installed version
  14815.             if (!isset($parr['version']) && !isset($parr['state']) && $version
  14816.                   && !isset($this->_options['downloadonly'])) {
  14817.                 $url = $this->_remote->call('package.getDownloadURL', $parr, $state, $version);
  14818.             } else {
  14819.                 $url = $this->_remote->call('package.getDownloadURL', $parr, $state);
  14820.             }
  14821.         } else {
  14822.             $url = $this->_remote->call('package.getDownloadURL', $parr, $state);
  14823.         }
  14824.         if (PEAR::isError($url)) {
  14825.             return $url;
  14826.         }
  14827.         if ($parr['channel'] != $curchannel) {
  14828.             $this->configSet('default_channel', $curchannel);
  14829.         }
  14830.         if (isset($url['__PEAR_ERROR_CLASS__'])) {
  14831.             return PEAR::raiseError($url['message']);
  14832.         }
  14833.         if (!is_array($url)) {
  14834.             return $url;
  14835.         }
  14836.         $url['raw'] = $url['info'];
  14837.         if (isset($this->_options['downloadonly'])) {
  14838.             $pkg = &$this->getPackagefileObject($this->config, $this->debug);
  14839.         } else {
  14840.             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  14841.             if (PEAR::isError($dir = $this->getDownloadDir())) {
  14842.                 PEAR::staticPopErrorHandling();
  14843.                 return $dir;
  14844.             }
  14845.             PEAR::staticPopErrorHandling();
  14846.             $pkg = &$this->getPackagefileObject($this->config, $this->debug, $dir);
  14847.         }
  14848.         PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  14849.         $pinfo = &$pkg->fromXmlString($url['info'], PEAR_VALIDATE_DOWNLOADING, 'remote');
  14850.         PEAR::staticPopErrorHandling();
  14851.         if (PEAR::isError($pinfo)) {
  14852.             if (!isset($this->_options['soft'])) {
  14853.                 $this->log(0, $pinfo->getMessage());
  14854.             }
  14855.             return PEAR::raiseError('Remote package.xml is not valid - this should never happen');
  14856.         }
  14857.         $url['info'] = &$pinfo;
  14858.         if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) {
  14859.             $ext = '.tar';
  14860.         } else {
  14861.             $ext = '.tgz';
  14862.         }
  14863.         if (is_array($url)) {
  14864.             if (isset($url['url'])) {
  14865.                 $url['url'] .= $ext;
  14866.             }
  14867.         }
  14868.         return $url;
  14869.     }
  14870.     // }}}
  14871.     // {{{ getDepPackageDownloadUrl()
  14872.  
  14873.     /**
  14874.      * @param array dependency array
  14875.      * @access private
  14876.      */
  14877.     function _getDepPackageDownloadUrl($dep, $parr)
  14878.     {
  14879.         $xsdversion = isset($dep['rel']) ? '1.0' : '2.0';
  14880.         $curchannel = $this->config->get('default_channel');
  14881.         if (isset($dep['uri'])) {
  14882.             $xsdversion = '2.0';
  14883.             $chan = &$this->_registry->getChannel('__uri');
  14884.             if (PEAR::isError($chan)) {
  14885.                 return $chan;
  14886.             }
  14887.             $version = $this->_registry->packageInfo($dep['name'], 'version', '__uri');
  14888.             $this->configSet('default_channel', '__uri');
  14889.         } else {
  14890.             if (isset($dep['channel'])) {
  14891.                 $remotechannel = $dep['channel'];
  14892.             } else {
  14893.                 $remotechannel = 'pear.php.net';
  14894.             }
  14895.             if (!$this->_registry->channelExists($remotechannel)) {
  14896.                 do {
  14897.                     if ($this->config->get('auto_discover')) {
  14898.                         if ($this->discover($remotechannel)) {
  14899.                             break;
  14900.                         }
  14901.                     }
  14902.                     return PEAR::raiseError('Unknown remote channel: ' . $remotechannel);
  14903.                 } while (false);
  14904.             }
  14905.             $chan = &$this->_registry->getChannel($remotechannel);
  14906.             if (PEAR::isError($chan)) {
  14907.                 return $chan;
  14908.             }
  14909.             $version = $this->_registry->packageInfo($dep['name'], 'version',
  14910.                 $remotechannel);
  14911.             $this->configSet('default_channel', $remotechannel);
  14912.         }
  14913.         $state = isset($parr['state']) ? $parr['state'] : $this->config->get('preferred_state');
  14914.         if (isset($parr['state']) && isset($parr['version'])) {
  14915.             unset($parr['state']);
  14916.         }
  14917.         if (isset($dep['uri'])) {
  14918.             $info = &$this->newDownloaderPackage($this);
  14919.             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  14920.             $err = $info->initialize($dep);
  14921.             PEAR::staticPopErrorHandling();
  14922.             if (!$err) {
  14923.                 // skip parameters that were missed by preferred_state
  14924.                 return PEAR::raiseError('Cannot initialize dependency');
  14925.             }
  14926.             if (PEAR::isError($err)) {
  14927.                 if (!isset($this->_options['soft'])) {
  14928.                     $this->log(0, $err->getMessage());
  14929.                 }
  14930.                 if (is_object($info)) {
  14931.                     $param = $info->getChannel() . '/' . $info->getPackage();
  14932.                 }
  14933.                 return PEAR::raiseError('Package "' . $param . '" is not valid');
  14934.             }
  14935.             return $info;
  14936.         } elseif ($chan->supportsREST($this->config->get('preferred_mirror')) &&
  14937.               $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) {
  14938.             $rest = &$this->config->getREST('1.0', $this->_options);
  14939.             $url = $rest->getDepDownloadURL($base, $xsdversion, $dep, $parr,
  14940.                     $state, $version);
  14941.             if (PEAR::isError($url)) {
  14942.                 return $url;
  14943.             }
  14944.             if ($parr['channel'] != $curchannel) {
  14945.                 $this->configSet('default_channel', $curchannel);
  14946.             }
  14947.             if (!is_array($url)) {
  14948.                 return $url;
  14949.             }
  14950.             $url['raw'] = false; // no checking is necessary for REST
  14951.             if (!is_array($url['info'])) {
  14952.                 return PEAR::raiseError('Invalid remote dependencies retrieved from REST - ' .
  14953.                     'this should never happen');
  14954.             }
  14955.             if (isset($url['info']['required'])) {
  14956.                 if (!class_exists('PEAR_PackageFile_v2')) {
  14957.                     require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v2.php';
  14958.                 }
  14959.                 $pf = new PEAR_PackageFile_v2;
  14960.                 $pf->setRawChannel($remotechannel);
  14961.             } else {
  14962.                 if (!class_exists('PEAR_PackageFile_v1')) {
  14963.                     require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v1.php';
  14964.                 }
  14965.                 $pf = new PEAR_PackageFile_v1;
  14966.             }
  14967.             $pf->setRawPackage($url['package']);
  14968.             $pf->setDeps($url['info']);
  14969.             if ($url['compatible']) {
  14970.                 $pf->setCompatible($url['compatible']);
  14971.             }
  14972.             $pf->setRawState($url['stability']);
  14973.             $url['info'] = &$pf;
  14974.             if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) {
  14975.                 $ext = '.tar';
  14976.             } else {
  14977.                 $ext = '.tgz';
  14978.             }
  14979.             if (is_array($url)) {
  14980.                 if (isset($url['url'])) {
  14981.                     $url['url'] .= $ext;
  14982.                 }
  14983.             }
  14984.             return $url;
  14985.         } elseif ($chan->supports('xmlrpc', 'package.getDepDownloadURL', false, '1.1')) {
  14986.             if ($version) {
  14987.                 $url = $this->_remote->call('package.getDepDownloadURL', $xsdversion, $dep, $parr,
  14988.                     $state, $version);
  14989.             } else {
  14990.                 $url = $this->_remote->call('package.getDepDownloadURL', $xsdversion, $dep, $parr,
  14991.                     $state);
  14992.             }
  14993.         } else {
  14994.             $url = $this->_remote->call('package.getDepDownloadURL', $xsdversion, $dep, $parr, $state);
  14995.         }
  14996.         if ($this->config->get('default_channel') != $curchannel) {
  14997.             $this->configSet('default_channel', $curchannel);
  14998.         }
  14999.         if (!is_array($url)) {
  15000.             return $url;
  15001.         }
  15002.         if (isset($url['__PEAR_ERROR_CLASS__'])) {
  15003.             return PEAR::raiseError($url['message']);
  15004.         }
  15005.         $url['raw'] = $url['info'];
  15006.         $pkg = &$this->getPackagefileObject($this->config, $this->debug);
  15007.         PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  15008.         $pinfo = &$pkg->fromXmlString($url['info'], PEAR_VALIDATE_DOWNLOADING, 'remote');
  15009.         PEAR::staticPopErrorHandling();
  15010.         if (PEAR::isError($pinfo)) {
  15011.             if (!isset($this->_options['soft'])) {
  15012.                 $this->log(0, $pinfo->getMessage());
  15013.             }
  15014.             return PEAR::raiseError('Remote package.xml is not valid - this should never happen');
  15015.         }
  15016.         $url['info'] = &$pinfo;
  15017.         if (is_array($url)) {
  15018.             if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) {
  15019.                 $ext = '.tar';
  15020.             } else {
  15021.                 $ext = '.tgz';
  15022.             }
  15023.             if (isset($url['url'])) {
  15024.                 $url['url'] .= $ext;
  15025.             }
  15026.         }
  15027.         return $url;
  15028.     }
  15029.     // }}}
  15030.     // {{{ getPackageDownloadUrl()
  15031.  
  15032.     /**
  15033.      * @deprecated in favor of _getPackageDownloadUrl
  15034.      */
  15035.     function getPackageDownloadUrl($package, $version = null, $channel = false)
  15036.     {
  15037.         if ($version) {
  15038.             $package .= "-$version";
  15039.         }
  15040.         if ($this === null || $this->_registry === null) {
  15041.             $package = "http://pear.php.net/get/$package";
  15042.         } else {
  15043.             $chan = $this->_registry->getChannel($channel);
  15044.             if (PEAR::isError($chan)) {
  15045.                 return '';
  15046.             }
  15047.             $package = "http://" . $chan->getServer() . "/get/$package";
  15048.         }
  15049.         if (!extension_loaded("zlib")) {
  15050.             $package .= '?uncompress=yes';
  15051.         }
  15052.         return $package;
  15053.     }
  15054.  
  15055.     // }}}
  15056.     // {{{ getDownloadedPackages()
  15057.  
  15058.     /**
  15059.      * Retrieve a list of downloaded packages after a call to {@link download()}.
  15060.      *
  15061.      * Also resets the list of downloaded packages.
  15062.      * @return array
  15063.      */
  15064.     function getDownloadedPackages()
  15065.     {
  15066.         $ret = $this->_downloadedPackages;
  15067.         $this->_downloadedPackages = array();
  15068.         $this->_toDownload = array();
  15069.         return $ret;
  15070.     }
  15071.  
  15072.     // }}}
  15073.     // {{{ _downloadCallback()
  15074.  
  15075.     function _downloadCallback($msg, $params = null)
  15076.     {
  15077.         switch ($msg) {
  15078.             case 'saveas':
  15079.                 $this->log(1, "downloading $params ...");
  15080.                 break;
  15081.             case 'done':
  15082.                 $this->log(1, '...done: ' . number_format($params, 0, '', ',') . ' bytes');
  15083.                 break;
  15084.             case 'bytesread':
  15085.                 static $bytes;
  15086.                 if (empty($bytes)) {
  15087.                     $bytes = 0;
  15088.                 }
  15089.                 if (!($bytes % 10240)) {
  15090.                     $this->log(1, '.', false);
  15091.                 }
  15092.                 $bytes += $params;
  15093.                 break;
  15094.             case 'start':
  15095.                 if($params[1] == -1) {
  15096.                     $length = "Unknown size";
  15097.                 } else {
  15098.                     $length = number_format($params[1], 0, '', ',')." bytes";
  15099.                 }
  15100.                 $this->log(1, "Starting to download {$params[0]} ($length)");
  15101.                 break;
  15102.         }
  15103.         if (method_exists($this->ui, '_downloadCallback'))
  15104.             $this->ui->_downloadCallback($msg, $params);
  15105.     }
  15106.  
  15107.     // }}}
  15108.     // {{{ _prependPath($path, $prepend)
  15109.  
  15110.     function _prependPath($path, $prepend)
  15111.     {
  15112.         if (strlen($prepend) > 0) {
  15113.             if (OS_WINDOWS && preg_match('/^[a-z]:/i', $path)) {
  15114.                 if (preg_match('/^[a-z]:/i', $prepend)) {
  15115.                     $prepend = substr($prepend, 2);
  15116.                 } elseif ($prepend{0} != '\\') {
  15117.                     $prepend = "\\$prepend";
  15118.                 }
  15119.                 $path = substr($path, 0, 2) . $prepend . substr($path, 2);
  15120.             } else {
  15121.                 $path = $prepend . $path;
  15122.             }
  15123.         }
  15124.         return $path;
  15125.     }
  15126.     // }}}
  15127.     // {{{ pushError($errmsg, $code)
  15128.  
  15129.     /**
  15130.      * @param string
  15131.      * @param integer
  15132.      */
  15133.     function pushError($errmsg, $code = -1)
  15134.     {
  15135.         array_push($this->_errorStack, array($errmsg, $code));
  15136.     }
  15137.  
  15138.     // }}}
  15139.     // {{{ getErrorMsgs()
  15140.  
  15141.     function getErrorMsgs()
  15142.     {
  15143.         $msgs = array();
  15144.         $errs = $this->_errorStack;
  15145.         foreach ($errs as $err) {
  15146.             $msgs[] = $err[0];
  15147.         }
  15148.         $this->_errorStack = array();
  15149.         return $msgs;
  15150.     }
  15151.  
  15152.     // }}}
  15153.  
  15154.     /**
  15155.      * for BC
  15156.      */
  15157.     function sortPkgDeps(&$packages, $uninstall = false)
  15158.     {
  15159.         $uninstall ? 
  15160.             $this->sortPackagesForUninstall($packages) :
  15161.             $this->sortPackagesForInstall($packages);
  15162.     }
  15163.  
  15164.     /**
  15165.      * Sort a list of arrays of array(downloaded packagefilename) by dependency.
  15166.      *
  15167.      * This uses the topological sort method from graph theory, and the
  15168.      * Structures_Graph package to properly sort dependencies for installation.
  15169.      * @param array an array of downloaded PEAR_Downloader_Packages
  15170.      * @return array array of array(packagefilename, package.xml contents)
  15171.      */
  15172.     function sortPackagesForInstall(&$packages)
  15173.     {
  15174.         require_once 'phar://go-pear.phar/' . 'Structures/Graph.php';
  15175.         require_once 'phar://go-pear.phar/' . 'Structures/Graph/Node.php';
  15176.         require_once 'phar://go-pear.phar/' . 'Structures/Graph/Manipulator/TopologicalSorter.php';
  15177.         $depgraph = new Structures_Graph(true);
  15178.         $nodes = array();
  15179.         $reg = &$this->config->getRegistry();
  15180.         foreach ($packages as $i => $package) {
  15181.             $pname = $reg->parsedPackageNameToString(
  15182.                 array(
  15183.                     'channel' => $package->getChannel(),
  15184.                     'package' => strtolower($package->getPackage()),
  15185.                 ));
  15186.             $nodes[$pname] = new Structures_Graph_Node;
  15187.             $nodes[$pname]->setData($packages[$i]);
  15188.             $depgraph->addNode($nodes[$pname]);
  15189.         }
  15190.         $deplinks = array();
  15191.         foreach ($nodes as $package => $node) {
  15192.             $pf = &$node->getData();
  15193.             $pdeps = $pf->getDeps(true);
  15194.             if (!$pdeps) {
  15195.                 continue;
  15196.             }
  15197.             if ($pf->getPackagexmlVersion() == '1.0') {
  15198.                 foreach ($pdeps as $dep) {
  15199.                     if ($dep['type'] != 'pkg' ||
  15200.                           (isset($dep['optional']) && $dep['optional'] == 'yes')) {
  15201.                         continue;
  15202.                     }
  15203.                     $dname = $reg->parsedPackageNameToString(
  15204.                           array(
  15205.                               'channel' => 'pear.php.net',
  15206.                               'package' => strtolower($dep['name']),
  15207.                           ));
  15208.                     if (isset($nodes[$dname]))
  15209.                     {
  15210.                         if (!isset($deplinks[$dname])) {
  15211.                             $deplinks[$dname] = array();
  15212.                         }
  15213.                         $deplinks[$dname][$package] = 1;
  15214.                         // dependency is in installed packages
  15215.                         continue;
  15216.                     }
  15217.                     $dname = $reg->parsedPackageNameToString(
  15218.                           array(
  15219.                               'channel' => 'pecl.php.net',
  15220.                               'package' => strtolower($dep['name']),
  15221.                           ));
  15222.                     if (isset($nodes[$dname]))
  15223.                     {
  15224.                         if (!isset($deplinks[$dname])) {
  15225.                             $deplinks[$dname] = array();
  15226.                         }
  15227.                         $deplinks[$dname][$package] = 1;
  15228.                         // dependency is in installed packages
  15229.                         continue;
  15230.                     }
  15231.                 }
  15232.             } else {
  15233.                 // the only ordering we care about is:
  15234.                 // 1) subpackages must be installed before packages that depend on them
  15235.                 // 2) required deps must be installed before packages that depend on them
  15236.                 if (isset($pdeps['required']['subpackage'])) {
  15237.                     $t = $pdeps['required']['subpackage'];
  15238.                     if (!isset($t[0])) {
  15239.                         $t = array($t);
  15240.                     }
  15241.                     $this->_setupGraph($t, $reg, $deplinks, $nodes, $package);
  15242.                 }
  15243.                 if (isset($pdeps['group'])) {
  15244.                     if (!isset($pdeps['group'][0])) {
  15245.                         $pdeps['group'] = array($pdeps['group']);
  15246.                     }
  15247.                     foreach ($pdeps['group'] as $group) {
  15248.                         if (isset($group['subpackage'])) {
  15249.                             $t = $group['subpackage'];
  15250.                             if (!isset($t[0])) {
  15251.                                 $t = array($t);
  15252.                             }
  15253.                             $this->_setupGraph($t, $reg, $deplinks, $nodes, $package);
  15254.                         }
  15255.                     }
  15256.                 }
  15257.                 if (isset($pdeps['optional']['subpackage'])) {
  15258.                     $t = $pdeps['optional']['subpackage'];
  15259.                     if (!isset($t[0])) {
  15260.                         $t = array($t);
  15261.                     }
  15262.                     $this->_setupGraph($t, $reg, $deplinks, $nodes, $package);
  15263.                 }
  15264.                 if (isset($pdeps['required']['package'])) {
  15265.                     $t = $pdeps['required']['package'];
  15266.                     if (!isset($t[0])) {
  15267.                         $t = array($t);
  15268.                     }
  15269.                     $this->_setupGraph($t, $reg, $deplinks, $nodes, $package);
  15270.                 }
  15271.                 if (isset($pdeps['group'])) {
  15272.                     if (!isset($pdeps['group'][0])) {
  15273.                         $pdeps['group'] = array($pdeps['group']);
  15274.                     }
  15275.                     foreach ($pdeps['group'] as $group) {
  15276.                         if (isset($group['package'])) {
  15277.                             $t = $group['package'];
  15278.                             if (!isset($t[0])) {
  15279.                                 $t = array($t);
  15280.                             }
  15281.                             $this->_setupGraph($t, $reg, $deplinks, $nodes, $package);
  15282.                         }
  15283.                     }
  15284.                 }
  15285.             }
  15286.         }
  15287.         $this->_detectDepCycle($deplinks);
  15288.         foreach ($deplinks as $dependent => $parents) {
  15289.             foreach ($parents as $parent => $unused) {
  15290.                 $nodes[$dependent]->connectTo($nodes[$parent]);
  15291.             }
  15292.         }
  15293.         $installOrder = Structures_Graph_Manipulator_TopologicalSorter::sort($depgraph);
  15294.         $ret = array();
  15295.         for ($i = 0; $i < count($installOrder); $i++) {
  15296.             foreach ($installOrder[$i] as $index => $sortedpackage) {
  15297.                 $data = &$installOrder[$i][$index]->getData();
  15298.                 $ret[] = &$nodes[$reg->parsedPackageNameToString(
  15299.                           array(
  15300.                               'channel' => $data->getChannel(),
  15301.                               'package' => strtolower($data->getPackage()),
  15302.                           ))]->getData();
  15303.             }
  15304.         }
  15305.         $packages = $ret;
  15306.         return;
  15307.     }
  15308.  
  15309.     /**
  15310.      * Detect recursive links between dependencies and break the cycles
  15311.      *
  15312.      * @param array
  15313.      * @access private
  15314.      */
  15315.     function _detectDepCycle(&$deplinks)
  15316.     {
  15317.         do {
  15318.             $keepgoing = false;
  15319.             foreach ($deplinks as $dep => $parents) {
  15320.                 foreach ($parents as $parent => $unused) {
  15321.                     // reset the parent cycle detector
  15322.                     $this->_testCycle(null, null, null);
  15323.                     if ($this->_testCycle($dep, $deplinks, $parent)) {
  15324.                         $keepgoing = true;
  15325.                         unset($deplinks[$dep][$parent]);
  15326.                         if (count($deplinks[$dep]) == 0) {
  15327.                             unset($deplinks[$dep]);
  15328.                         }
  15329.                         continue 3;
  15330.                     }
  15331.                 }
  15332.             }
  15333.         } while ($keepgoing);
  15334.     }
  15335.  
  15336.     function _testCycle($test, $deplinks, $dep)
  15337.     {
  15338.         static $visited = array();
  15339.         if ($test === null) {
  15340.             $visited = array();
  15341.             return;
  15342.         }
  15343.         // this happens when a parent has a dep cycle on another dependency
  15344.         // but the child is not part of the cycle
  15345.         if (isset($visited[$dep])) {
  15346.             return false;
  15347.         }
  15348.         $visited[$dep] = 1;
  15349.         if ($test == $dep) {
  15350.             return true;
  15351.         }
  15352.         if (isset($deplinks[$dep])) {
  15353.             if (in_array($test, array_keys($deplinks[$dep]), true)) {
  15354.                 return true;
  15355.             }
  15356.             foreach ($deplinks[$dep] as $parent => $unused) {
  15357.                 if ($this->_testCycle($test, $deplinks, $parent)) {
  15358.                     return true;
  15359.                 }
  15360.             }
  15361.         }
  15362.         return false;
  15363.     }
  15364.  
  15365.     /**
  15366.      * Set up the dependency for installation parsing
  15367.      *
  15368.      * @param array $t dependency information
  15369.      * @param PEAR_Registry $reg
  15370.      * @param array $deplinks list of dependency links already established
  15371.      * @param array $nodes all existing package nodes
  15372.      * @param string $package parent package name
  15373.      * @access private
  15374.      */
  15375.     function _setupGraph($t, $reg, &$deplinks, &$nodes, $package)
  15376.     {
  15377.         foreach ($t as $dep) {
  15378.             $depchannel = !isset($dep['channel']) ?
  15379.                 '__uri': $dep['channel'];
  15380.             $dname = $reg->parsedPackageNameToString(
  15381.                   array(
  15382.                       'channel' => $depchannel,
  15383.                       'package' => strtolower($dep['name']),
  15384.                   ));
  15385.             if (isset($nodes[$dname]))
  15386.             {
  15387.                 if (!isset($deplinks[$dname])) {
  15388.                     $deplinks[$dname] = array();
  15389.                 }
  15390.                 $deplinks[$dname][$package] = 1;
  15391.             }
  15392.         }
  15393.     }
  15394.  
  15395.     function _dependsOn($a, $b)
  15396.     {
  15397.         return $this->_checkDepTree(strtolower($a->getChannel()), strtolower($a->getPackage()),
  15398.             $b);
  15399.     }
  15400.  
  15401.     function _checkDepTree($channel, $package, $b, $checked = array())
  15402.     {
  15403.         $checked[$channel][$package] = true;
  15404.         if (!isset($this->_depTree[$channel][$package])) {
  15405.             return false;
  15406.         }
  15407.         if (isset($this->_depTree[$channel][$package][strtolower($b->getChannel())]
  15408.               [strtolower($b->getPackage())])) {
  15409.             return true;
  15410.         }
  15411.         foreach ($this->_depTree[$channel][$package] as $ch => $packages) {
  15412.             foreach ($packages as $pa => $true) {
  15413.                 if ($this->_checkDepTree($ch, $pa, $b, $checked)) {
  15414.                     return true;
  15415.                 }
  15416.             }
  15417.         }
  15418.         return false;
  15419.     }
  15420.  
  15421.     function _sortInstall($a, $b)
  15422.     {
  15423.         if (!$a->getDeps() && !$b->getDeps()) {
  15424.             return 0; // neither package has dependencies, order is insignificant
  15425.         }
  15426.         if ($a->getDeps() && !$b->getDeps()) {
  15427.             return 1; // $a must be installed after $b because $a has dependencies
  15428.         }
  15429.         if (!$a->getDeps() && $b->getDeps()) {
  15430.             return -1; // $b must be installed after $a because $b has dependencies
  15431.         }
  15432.         // both packages have dependencies
  15433.         if ($this->_dependsOn($a, $b)) {
  15434.             return 1;
  15435.         }
  15436.         if ($this->_dependsOn($b, $a)) {
  15437.             return -1;
  15438.         }
  15439.         return 0;
  15440.     }
  15441.  
  15442.     /**
  15443.      * Download a file through HTTP.  Considers suggested file name in
  15444.      * Content-disposition: header and can run a callback function for
  15445.      * different events.  The callback will be called with two
  15446.      * parameters: the callback type, and parameters.  The implemented
  15447.      * callback types are:
  15448.      *
  15449.      *  'setup'       called at the very beginning, parameter is a UI object
  15450.      *                that should be used for all output
  15451.      *  'message'     the parameter is a string with an informational message
  15452.      *  'saveas'      may be used to save with a different file name, the
  15453.      *                parameter is the filename that is about to be used.
  15454.      *                If a 'saveas' callback returns a non-empty string,
  15455.      *                that file name will be used as the filename instead.
  15456.      *                Note that $save_dir will not be affected by this, only
  15457.      *                the basename of the file.
  15458.      *  'start'       download is starting, parameter is number of bytes
  15459.      *                that are expected, or -1 if unknown
  15460.      *  'bytesread'   parameter is the number of bytes read so far
  15461.      *  'done'        download is complete, parameter is the total number
  15462.      *                of bytes read
  15463.      *  'connfailed'  if the TCP/SSL connection fails, this callback is called
  15464.      *                with array(host,port,errno,errmsg)
  15465.      *  'writefailed' if writing to disk fails, this callback is called
  15466.      *                with array(destfile,errmsg)
  15467.      *
  15468.      * If an HTTP proxy has been configured (http_proxy PEAR_Config
  15469.      * setting), the proxy will be used.
  15470.      *
  15471.      * @param string  $url       the URL to download
  15472.      * @param object  $ui        PEAR_Frontend_* instance
  15473.      * @param object  $config    PEAR_Config instance
  15474.      * @param string  $save_dir  directory to save file in
  15475.      * @param mixed   $callback  function/method to call for status
  15476.      *                           updates
  15477.      * @param false|string|array $lastmodified header values to check against for caching
  15478.      *                           use false to return the header values from this download
  15479.      * @param false|array $accept Accept headers to send
  15480.      * @param false|string $channel Channel to use for retrieving authentication
  15481.      * @return string|array  Returns the full path of the downloaded file or a PEAR
  15482.      *                       error on failure.  If the error is caused by
  15483.      *                       socket-related errors, the error object will
  15484.      *                       have the fsockopen error code available through
  15485.      *                       getCode().  If caching is requested, then return the header
  15486.      *                       values.
  15487.      *
  15488.      * @access public
  15489.      */
  15490.     function downloadHttp($url, &$ui, $save_dir = '.', $callback = null, $lastmodified = null,
  15491.                           $accept = false, $channel = false)
  15492.     {
  15493.         static $redirect = 0;
  15494.         // allways reset , so we are clean case of error
  15495.         $wasredirect = $redirect;
  15496.         $redirect = 0;
  15497.         if ($callback) {
  15498.             call_user_func($callback, 'setup', array(&$ui));
  15499.         }
  15500.         $info = parse_url($url);
  15501.         if (!isset($info['scheme']) || !in_array($info['scheme'], array('http', 'https'))) {
  15502.             return PEAR::raiseError('Cannot download non-http URL "' . $url . '"');
  15503.         }
  15504.         if (!isset($info['host'])) {
  15505.             return PEAR::raiseError('Cannot download from non-URL "' . $url . '"');
  15506.         } else {
  15507.             $host = isset($info['host']) ? $info['host'] : null;
  15508.             $port = isset($info['port']) ? $info['port'] : null;
  15509.             $path = isset($info['path']) ? $info['path'] : null;
  15510.         }
  15511.         if (isset($this)) {
  15512.             $config = &$this->config;
  15513.         } else {
  15514.             $config = &PEAR_Config::singleton();
  15515.         }
  15516.         $proxy_host = $proxy_port = $proxy_user = $proxy_pass = '';
  15517.         if ($config->get('http_proxy') && 
  15518.               $proxy = parse_url($config->get('http_proxy'))) {
  15519.             $proxy_host = isset($proxy['host']) ? $proxy['host'] : null;
  15520.             if (isset($proxy['scheme']) && $proxy['scheme'] == 'https') {
  15521.                 $proxy_host = 'ssl://' . $proxy_host;
  15522.             }
  15523.             $proxy_port = isset($proxy['port']) ? $proxy['port'] : 8080;
  15524.             $proxy_user = isset($proxy['user']) ? urldecode($proxy['user']) : null;
  15525.             $proxy_pass = isset($proxy['pass']) ? urldecode($proxy['pass']) : null;
  15526.  
  15527.             if ($callback) {
  15528.                 call_user_func($callback, 'message', "Using HTTP proxy $host:$port");
  15529.             }
  15530.         }
  15531.         if (empty($port)) {
  15532.             if (isset($info['scheme']) && $info['scheme'] == 'https') {
  15533.                 $port = 443;
  15534.             } else {
  15535.                 $port = 80;
  15536.             }
  15537.         }
  15538.         if ($proxy_host != '') {
  15539.             $fp = @fsockopen($proxy_host, $proxy_port, $errno, $errstr);
  15540.             if (!$fp) {
  15541.                 if ($callback) {
  15542.                     call_user_func($callback, 'connfailed', array($proxy_host, $proxy_port,
  15543.                                                                   $errno, $errstr));
  15544.                 }
  15545.                 return PEAR::raiseError("Connection to `$proxy_host:$proxy_port' failed: $errstr", $errno);
  15546.             }
  15547.             if ($lastmodified === false || $lastmodified) {
  15548.                 $request = "GET $url HTTP/1.1\r\n";
  15549.             } else {
  15550.                 $request = "GET $url HTTP/1.0\r\n";
  15551.             }
  15552.         } else {
  15553.             if (isset($info['scheme']) && $info['scheme'] == 'https') {
  15554.                 $host = 'ssl://' . $host;
  15555.             }
  15556.             $fp = @fsockopen($host, $port, $errno, $errstr);
  15557.             if (!$fp) {
  15558.                 if ($callback) {
  15559.                     call_user_func($callback, 'connfailed', array($host, $port,
  15560.                                                                   $errno, $errstr));
  15561.                 }
  15562.                 return PEAR::raiseError("Connection to `$host:$port' failed: $errstr", $errno);
  15563.             }
  15564.             if ($lastmodified === false || $lastmodified) {
  15565.                 $request = "GET $path HTTP/1.1\r\n";
  15566.                 $request .= "Host: $host:$port\r\n";
  15567.             } else {
  15568.                 $request = "GET $path HTTP/1.0\r\n";
  15569.                 $request .= "Host: $host\r\n";
  15570.             }
  15571.         }
  15572.         $ifmodifiedsince = '';
  15573.         if (is_array($lastmodified)) {
  15574.             if (isset($lastmodified['Last-Modified'])) {
  15575.                 $ifmodifiedsince = 'If-Modified-Since: ' . $lastmodified['Last-Modified'] . "\r\n";
  15576.             }
  15577.             if (isset($lastmodified['ETag'])) {
  15578.                 $ifmodifiedsince .= "If-None-Match: $lastmodified[ETag]\r\n";
  15579.             }
  15580.         } else {
  15581.             $ifmodifiedsince = ($lastmodified ? "If-Modified-Since: $lastmodified\r\n" : '');
  15582.         }
  15583.         $request .= $ifmodifiedsince . "User-Agent: PEAR/1.7.1/PHP/" .
  15584.             PHP_VERSION . "\r\n";
  15585.         if (isset($this)) { // only pass in authentication for non-static calls
  15586.             $username = $config->get('username', null, $channel);
  15587.             $password = $config->get('password', null, $channel);
  15588.             if ($username && $password) {
  15589.                 $tmp = base64_encode("$username:$password");
  15590.                 $request .= "Authorization: Basic $tmp\r\n";
  15591.             }
  15592.         }
  15593.         if ($proxy_host != '' && $proxy_user != '') {
  15594.             $request .= 'Proxy-Authorization: Basic ' .
  15595.                 base64_encode($proxy_user . ':' . $proxy_pass) . "\r\n";
  15596.         }
  15597.         if ($accept) {
  15598.             $request .= 'Accept: ' . implode(', ', $accept) . "\r\n";
  15599.         }
  15600.         $request .= "Connection: close\r\n";
  15601.         $request .= "\r\n";
  15602.         fwrite($fp, $request);
  15603.         $headers = array();
  15604.         $reply = 0;
  15605.         while (trim($line = fgets($fp, 1024))) {
  15606.             if (preg_match('/^([^:]+):\s+(.*)\s*\\z/', $line, $matches)) {
  15607.                 $headers[strtolower($matches[1])] = trim($matches[2]);
  15608.             } elseif (preg_match('|^HTTP/1.[01] ([0-9]{3}) |', $line, $matches)) {
  15609.                 $reply = (int) $matches[1];
  15610.                 if ($reply == 304 && ($lastmodified || ($lastmodified === false))) {
  15611.                     return false;
  15612.                 }
  15613.                 if (! in_array($reply, array(200, 301, 302, 303, 305, 307))) {
  15614.                     return PEAR::raiseError("File http://$host:$port$path not valid (received: $line)");
  15615.                 }
  15616.             }
  15617.         }
  15618.         if ($reply != 200) {
  15619.             if (isset($headers['location'])) {
  15620.                 if ($wasredirect < 5) {
  15621.                     $redirect = $wasredirect + 1;
  15622.                     return $this->downloadHttp($headers['location'],
  15623.                             $ui, $save_dir, $callback, $lastmodified, $accept);
  15624.                 } else {
  15625.                     return PEAR::raiseError("File http://$host:$port$path not valid (redirection looped more than 5 times)");
  15626.                 }
  15627.             } else {
  15628.                 return PEAR::raiseError("File http://$host:$port$path not valid (redirected but no location)");
  15629.             }
  15630.         }
  15631.         if (isset($headers['content-disposition']) &&
  15632.             preg_match('/\sfilename=\"([^;]*\S)\"\s*(;|\\z)/', $headers['content-disposition'], $matches)) {
  15633.             $save_as = basename($matches[1]);
  15634.         } else {
  15635.             $save_as = basename($url);
  15636.         }
  15637.         if ($callback) {
  15638.             $tmp = call_user_func($callback, 'saveas', $save_as);
  15639.             if ($tmp) {
  15640.                 $save_as = $tmp;
  15641.             }
  15642.         }
  15643.         $dest_file = $save_dir . DIRECTORY_SEPARATOR . $save_as;
  15644.         if (!$wp = @fopen($dest_file, 'wb')) {
  15645.             fclose($fp);
  15646.             if ($callback) {
  15647.                 call_user_func($callback, 'writefailed', array($dest_file, $php_errormsg));
  15648.             }
  15649.             return PEAR::raiseError("could not open $dest_file for writing");
  15650.         }
  15651.         if (isset($headers['content-length'])) {
  15652.             $length = $headers['content-length'];
  15653.         } else {
  15654.             $length = -1;
  15655.         }
  15656.         $bytes = 0;
  15657.         if ($callback) {
  15658.             call_user_func($callback, 'start', array(basename($dest_file), $length));
  15659.         }
  15660.         while ($data = fread($fp, 1024)) {
  15661.             $bytes += strlen($data);
  15662.             if ($callback) {
  15663.                 call_user_func($callback, 'bytesread', $bytes);
  15664.             }
  15665.             if (!@fwrite($wp, $data)) {
  15666.                 fclose($fp);
  15667.                 if ($callback) {
  15668.                     call_user_func($callback, 'writefailed', array($dest_file, $php_errormsg));
  15669.                 }
  15670.                 return PEAR::raiseError("$dest_file: write failed ($php_errormsg)");
  15671.             }
  15672.         }
  15673.         fclose($fp);
  15674.         fclose($wp);
  15675.         if ($callback) {
  15676.             call_user_func($callback, 'done', $bytes);
  15677.         }
  15678.         if ($lastmodified === false || $lastmodified) {
  15679.             if (isset($headers['etag'])) {
  15680.                 $lastmodified = array('ETag' => $headers['etag']);
  15681.             }
  15682.             if (isset($headers['last-modified'])) {
  15683.                 if (is_array($lastmodified)) {
  15684.                     $lastmodified['Last-Modified'] = $headers['last-modified'];
  15685.                 } else {
  15686.                     $lastmodified = $headers['last-modified'];
  15687.                 }
  15688.             }
  15689.             return array($dest_file, $lastmodified, $headers);
  15690.         }
  15691.         return $dest_file;
  15692.     }
  15693. }
  15694. // }}}
  15695.  
  15696. ?>
  15697. <?php
  15698. /**
  15699.  * PEAR_Downloader_Package
  15700.  *
  15701.  * PHP versions 4 and 5
  15702.  *
  15703.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  15704.  * that is available through the world-wide-web at the following URI:
  15705.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  15706.  * the PHP License and are unable to obtain it through the web, please
  15707.  * send a note to license@php.net so we can mail you a copy immediately.
  15708.  *
  15709.  * @category   pear
  15710.  * @package    PEAR
  15711.  * @author     Greg Beaver <cellog@php.net>
  15712.  * @copyright  1997-2008 The PHP Group
  15713.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  15714.  * @version    CVS: $Id: Package.php,v 1.112 2008/01/03 20:26:36 cellog Exp $
  15715.  * @link       http://pear.php.net/package/PEAR
  15716.  * @since      File available since Release 1.4.0a1
  15717.  */
  15718. /**
  15719.  * Error code when parameter initialization fails because no releases
  15720.  * exist within preferred_state, but releases do exist
  15721.  */
  15722. define('PEAR_DOWNLOADER_PACKAGE_STATE', -1003);
  15723. /**
  15724.  * Error code when parameter initialization fails because no releases
  15725.  * exist that will work with the existing PHP version
  15726.  */
  15727. define('PEAR_DOWNLOADER_PACKAGE_PHPVERSION', -1004);
  15728. /**
  15729.  * Coordinates download parameters and manages their dependencies
  15730.  * prior to downloading them.
  15731.  *
  15732.  * Input can come from three sources:
  15733.  *
  15734.  * - local files (archives or package.xml)
  15735.  * - remote files (downloadable urls)
  15736.  * - abstract package names
  15737.  *
  15738.  * The first two elements are handled cleanly by PEAR_PackageFile, but the third requires
  15739.  * accessing pearweb's xml-rpc interface to determine necessary dependencies, and the
  15740.  * format returned of dependencies is slightly different from that used in package.xml.
  15741.  *
  15742.  * This class hides the differences between these elements, and makes automatic
  15743.  * dependency resolution a piece of cake.  It also manages conflicts when
  15744.  * two classes depend on incompatible dependencies, or differing versions of the same
  15745.  * package dependency.  In addition, download will not be attempted if the php version is
  15746.  * not supported, PEAR installer version is not supported, or non-PECL extensions are not
  15747.  * installed.
  15748.  * @category   pear
  15749.  * @package    PEAR
  15750.  * @author     Greg Beaver <cellog@php.net>
  15751.  * @copyright  1997-2008 The PHP Group
  15752.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  15753.  * @version    Release: 1.7.1
  15754.  * @link       http://pear.php.net/package/PEAR
  15755.  * @since      Class available since Release 1.4.0a1
  15756.  */
  15757. class PEAR_Downloader_Package
  15758. {
  15759.     /**
  15760.      * @var PEAR_Downloader
  15761.      */
  15762.     var $_downloader;
  15763.     /**
  15764.      * @var PEAR_Config
  15765.      */
  15766.     var $_config;
  15767.     /**
  15768.      * @var PEAR_Registry
  15769.      */
  15770.     var $_registry;
  15771.     /**
  15772.      * Used to implement packagingroot properly
  15773.      * @var PEAR_Registry
  15774.      */
  15775.     var $_installRegistry;
  15776.     /**
  15777.      * @var PEAR_PackageFile_v1|PEAR_PackageFile|v2
  15778.      */
  15779.     var $_packagefile;
  15780.     /**
  15781.      * @var array
  15782.      */
  15783.     var $_parsedname;
  15784.     /**
  15785.      * @var array
  15786.      */
  15787.     var $_downloadURL;
  15788.     /**
  15789.      * @var array
  15790.      */
  15791.     var $_downloadDeps = array();
  15792.     /**
  15793.      * @var boolean
  15794.      */
  15795.     var $_valid = false;
  15796.     /**
  15797.      * @var boolean
  15798.      */
  15799.     var $_analyzed = false;
  15800.     /**
  15801.      * if this or a parent package was invoked with Package-state, this is set to the
  15802.      * state variable.
  15803.      *
  15804.      * This allows temporary reassignment of preferred_state for a parent package and all of
  15805.      * its dependencies.
  15806.      * @var string|false
  15807.      */
  15808.     var $_explicitState = false;
  15809.     /**
  15810.      * If this package is invoked with Package#group, this variable will be true
  15811.      */
  15812.     var $_explicitGroup = false;
  15813.     /**
  15814.      * Package type local|url|xmlrpc
  15815.      * @var string
  15816.      */
  15817.     var $_type;
  15818.     /**
  15819.      * Contents of package.xml, if downloaded from a remote channel
  15820.      * @var string|false
  15821.      * @access private
  15822.      */
  15823.     var $_rawpackagefile;
  15824.     /**
  15825.      * @var boolean
  15826.      * @access private
  15827.      */
  15828.     var $_validated = false;
  15829.  
  15830.     /**
  15831.      * @param PEAR_Downloader
  15832.      */
  15833.     function PEAR_Downloader_Package(&$downloader)
  15834.     {
  15835.         $this->_downloader = &$downloader;
  15836.         $this->_config = &$this->_downloader->config;
  15837.         $this->_registry = &$this->_config->getRegistry();
  15838.         $options = $downloader->getOptions();
  15839.         if (isset($options['packagingroot'])) {
  15840.             $this->_config->setInstallRoot($options['packagingroot']);
  15841.             $this->_installRegistry = &$this->_config->getRegistry();
  15842.             $this->_config->setInstallRoot(false);
  15843.         } else {
  15844.             $this->_installRegistry = &$this->_registry;
  15845.         }
  15846.         $this->_valid = $this->_analyzed = false;
  15847.     }
  15848.  
  15849.     /**
  15850.      * Parse the input and determine whether this is a local file, a remote uri, or an
  15851.      * abstract package name.
  15852.      *
  15853.      * This is the heart of the PEAR_Downloader_Package(), and is used in
  15854.      * {@link PEAR_Downloader::download()}
  15855.      * @param string
  15856.      * @return bool|PEAR_Error
  15857.      */
  15858.     function initialize($param)
  15859.     {
  15860.         $origErr = $this->_fromFile($param);
  15861.         if (!$this->_valid) {
  15862.             $options = $this->_downloader->getOptions();
  15863.             if (isset($options['offline'])) {
  15864.                 if (PEAR::isError($origErr)) {
  15865.                     if (!isset($options['soft'])) {
  15866.                         $this->_downloader->log(0, $origErr->getMessage());
  15867.                     }
  15868.                 }
  15869.                 return PEAR::raiseError('Cannot download non-local package "' . $param . '"');
  15870.             }
  15871.             $err = $this->_fromUrl($param);
  15872.             if (PEAR::isError($err) || !$this->_valid) {
  15873.                 if ($this->_type == 'url') {
  15874.                     if (PEAR::isError($err)) {
  15875.                         if (!isset($options['soft'])) {
  15876.                             $this->_downloader->log(0, $err->getMessage());
  15877.                         }
  15878.                     }
  15879.                     return PEAR::raiseError("Invalid or missing remote package file");
  15880.                 }
  15881.                 $err = $this->_fromString($param);
  15882.                 if (PEAR::isError($err) || !$this->_valid) {
  15883.                     if (PEAR::isError($err) &&
  15884.                           $err->getCode() == PEAR_DOWNLOADER_PACKAGE_STATE) {
  15885.                         return false; // instruct the downloader to silently skip
  15886.                     }
  15887.                     if (isset($this->_type) && $this->_type == 'local' &&
  15888.                           PEAR::isError($origErr)) {
  15889.                         if (is_array($origErr->getUserInfo())) {
  15890.                             foreach ($origErr->getUserInfo() as $err) {
  15891.                                 if (is_array($err)) {
  15892.                                     $err = $err['message'];
  15893.                                 }
  15894.                                 if (!isset($options['soft'])) {
  15895.                                     $this->_downloader->log(0, $err);
  15896.                                 }
  15897.                             }
  15898.                         }
  15899.                         if (!isset($options['soft'])) {
  15900.                             $this->_downloader->log(0, $origErr->getMessage());
  15901.                         }
  15902.                         if (is_array($param)) {
  15903.                             $param = $this->_registry->parsedPackageNameToString($param,
  15904.                                 true);
  15905.                         }
  15906.                         return PEAR::raiseError(
  15907.                             "Cannot initialize '$param', invalid or missing package file");
  15908.                     }
  15909.                     if (PEAR::isError($err)) {
  15910.                         if (!isset($options['soft'])) {
  15911.                             $this->_downloader->log(0, $err->getMessage());
  15912.                         }
  15913.                     }
  15914.                     if (is_array($param)) {
  15915.                         $param = $this->_registry->parsedPackageNameToString($param, true);
  15916.                     }
  15917.                     return PEAR::raiseError(
  15918.                         "Cannot initialize '$param', invalid or missing package file");
  15919.                 }
  15920.             }
  15921.         }
  15922.         return true;
  15923.     }
  15924.  
  15925.     /**
  15926.      * Retrieve any non-local packages
  15927.      * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|PEAR_Error
  15928.      */
  15929.     function &download()
  15930.     {
  15931.         if (isset($this->_packagefile)) {
  15932.             return $this->_packagefile;
  15933.         }
  15934.         if (isset($this->_downloadURL['url'])) {
  15935.             $this->_isvalid = false;
  15936.             $info = $this->getParsedPackage();
  15937.             foreach ($info as $i => $p) {
  15938.                 $info[$i] = strtolower($p);
  15939.             }
  15940.             $err = $this->_fromUrl($this->_downloadURL['url'],
  15941.                 $this->_registry->parsedPackageNameToString($this->_parsedname, true));
  15942.             $newinfo = $this->getParsedPackage();
  15943.             foreach ($newinfo as $i => $p) {
  15944.                 $newinfo[$i] = strtolower($p);
  15945.             }
  15946.             if ($info != $newinfo) {
  15947.                 do {
  15948.                     if ($info['package'] == 'pecl.php.net' && $newinfo['package'] == 'pear.php.net') {
  15949.                         $info['package'] = 'pear.php.net';
  15950.                         if ($info == $newinfo) {
  15951.                             // skip the channel check if a pecl package says it's a PEAR package
  15952.                             break;
  15953.                         }
  15954.                     }
  15955.                     return PEAR::raiseError('CRITICAL ERROR: We are ' .
  15956.                         $this->_registry->parsedPackageNameToString($info) . ', but the file ' .
  15957.                         'downloaded claims to be ' .
  15958.                         $this->_registry->parsedPackageNameToString($this->getParsedPackage()));
  15959.                 } while (false);
  15960.             }
  15961.             if (PEAR::isError($err) || !$this->_valid) {
  15962.                 return $err;
  15963.             }
  15964.         }
  15965.         $this->_type = 'local';
  15966.         return $this->_packagefile;
  15967.     }
  15968.  
  15969.     function &getPackageFile()
  15970.     {
  15971.         return $this->_packagefile;
  15972.     }
  15973.  
  15974.     function &getDownloader()
  15975.     {
  15976.         return $this->_downloader;
  15977.     }
  15978.  
  15979.     function getType() 
  15980.     {
  15981.         return $this->_type;
  15982.     }
  15983.  
  15984.     /**
  15985.      * Like {@link initialize()}, but operates on a dependency
  15986.      */
  15987.     function fromDepURL($dep)
  15988.     {
  15989.         $this->_downloadURL = $dep;
  15990.         if (isset($dep['uri'])) {
  15991.             $options = $this->_downloader->getOptions();
  15992.             if (!extension_loaded("zlib") || isset($options['nocompress'])) {
  15993.                 $ext = '.tar';
  15994.             } else {
  15995.                 $ext = '.tgz';
  15996.             }
  15997.             PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  15998.             $err = $this->_fromUrl($dep['uri'] . $ext);
  15999.             PEAR::popErrorHandling();
  16000.             if (PEAR::isError($err)) {
  16001.                 if (!isset($options['soft'])) {
  16002.                     $this->_downloader->log(0, $err->getMessage());
  16003.                 }
  16004.                 return PEAR::raiseError('Invalid uri dependency "' . $dep['uri'] . $ext . '", ' .
  16005.                     'cannot download');
  16006.             }
  16007.         } else {
  16008.             $this->_parsedname =
  16009.                 array(
  16010.                     'package' => $dep['info']->getPackage(),
  16011.                     'channel' => $dep['info']->getChannel(),
  16012.                     'version' => $dep['version']
  16013.                 );
  16014.             if (!isset($dep['nodefault'])) {
  16015.                 $this->_parsedname['group'] = 'default'; // download the default dependency group
  16016.                 $this->_explicitGroup = false;
  16017.             }
  16018.             $this->_rawpackagefile = $dep['raw'];
  16019.         }
  16020.     }
  16021.  
  16022.     function detectDependencies($params)
  16023.     {
  16024.         $options = $this->_downloader->getOptions();
  16025.         if (isset($options['downloadonly'])) {
  16026.             return;
  16027.         }
  16028.         if (isset($options['offline'])) {
  16029.             $this->_downloader->log(3, 'Skipping dependency download check, --offline specified');
  16030.             return;
  16031.         }
  16032.         $pname = $this->getParsedPackage();
  16033.         if (!$pname) {
  16034.             return;
  16035.         }
  16036.         $deps = $this->getDeps();
  16037.         if (!$deps) {
  16038.             return;
  16039.         }
  16040.         if (isset($deps['required'])) { // package.xml 2.0
  16041.             return $this->_detect2($deps, $pname, $options, $params);
  16042.         } else {
  16043.             return $this->_detect1($deps, $pname, $options, $params);
  16044.         }
  16045.     }
  16046.  
  16047.     function setValidated()
  16048.     {
  16049.         $this->_validated = true;
  16050.     }
  16051.  
  16052.     function alreadyValidated()
  16053.     {
  16054.         return $this->_validated;
  16055.     }
  16056.  
  16057.     /**
  16058.      * Remove packages to be downloaded that are already installed
  16059.      * @param array of PEAR_Downloader_Package objects
  16060.      * @static
  16061.      */
  16062.     function removeInstalled(&$params)
  16063.     {
  16064.         if (!isset($params[0])) {
  16065.             return;
  16066.         }
  16067.         $options = $params[0]->_downloader->getOptions();
  16068.         if (!isset($options['downloadonly'])) {
  16069.             foreach ($params as $i => $param) {
  16070.                 // remove self if already installed with this version
  16071.                 // this does not need any pecl magic - we only remove exact matches
  16072.                 if ($param->_installRegistry->packageExists($param->getPackage(), $param->getChannel())) {
  16073.                     if (version_compare($param->_installRegistry->packageInfo($param->getPackage(), 'version',
  16074.                           $param->getChannel()), $param->getVersion(), '==')) {
  16075.                         if (!isset($options['force'])) {
  16076.                             $info = $param->getParsedPackage();
  16077.                             unset($info['version']);
  16078.                             unset($info['state']);
  16079.                             if (!isset($options['soft'])) {
  16080.                                 $param->_downloader->log(1, 'Skipping package "' .
  16081.                                     $param->getShortName() .
  16082.                                     '", already installed as version ' .
  16083.                                     $param->_installRegistry->packageInfo($param->getPackage(),
  16084.                                         'version', $param->getChannel()));
  16085.                             }
  16086.                             $params[$i] = false;
  16087.                         }
  16088.                     } elseif (!isset($options['force']) && !isset($options['upgrade']) &&
  16089.                           !isset($options['soft'])) {
  16090.                         $info = $param->getParsedPackage();
  16091.                         $param->_downloader->log(1, 'Skipping package "' .
  16092.                             $param->getShortName() .
  16093.                             '", already installed as version ' .
  16094.                             $param->_installRegistry->packageInfo($param->getPackage(), 'version',
  16095.                                 $param->getChannel()));
  16096.                         $params[$i] = false;
  16097.                     }
  16098.                 }
  16099.             }
  16100.         }
  16101.         PEAR_Downloader_Package::removeDuplicates($params);
  16102.     }
  16103.  
  16104.     function _detect2($deps, $pname, $options, $params)
  16105.     {
  16106.         $this->_downloadDeps = array();
  16107.         $groupnotfound = false;
  16108.         foreach (array('package', 'subpackage') as $packagetype) {
  16109.             // get required dependency group
  16110.             if (isset($deps['required'][$packagetype])) {
  16111.                 if (isset($deps['required'][$packagetype][0])) {
  16112.                     foreach ($deps['required'][$packagetype] as $dep) {
  16113.                         if (isset($dep['conflicts'])) {
  16114.                             // skip any package that this package conflicts with
  16115.                             continue;
  16116.                         }
  16117.                         $ret = $this->_detect2Dep($dep, $pname, 'required', $params);
  16118.                         if (is_array($ret)) {
  16119.                             $this->_downloadDeps[] = $ret;
  16120.                         }
  16121.                     }
  16122.                 } else {
  16123.                     $dep = $deps['required'][$packagetype];
  16124.                     if (!isset($dep['conflicts'])) {
  16125.                         // skip any package that this package conflicts with
  16126.                         $ret = $this->_detect2Dep($dep, $pname, 'required', $params);
  16127.                         if (is_array($ret)) {
  16128.                             $this->_downloadDeps[] = $ret;
  16129.                         }
  16130.                     }
  16131.                 }
  16132.             }
  16133.             // get optional dependency group, if any
  16134.             if (isset($deps['optional'][$packagetype])) {
  16135.                 $skipnames = array();
  16136.                 if (!isset($deps['optional'][$packagetype][0])) {
  16137.                     $deps['optional'][$packagetype] = array($deps['optional'][$packagetype]);
  16138.                 }
  16139.                 foreach ($deps['optional'][$packagetype] as $dep) {
  16140.                     $skip = false;
  16141.                     if (!isset($options['alldeps'])) {
  16142.                         $dep['package'] = $dep['name'];
  16143.                         if (!isset($options['soft'])) {
  16144.                             $this->_downloader->log(3, 'Notice: package "' .
  16145.                               $this->_registry->parsedPackageNameToString($this->getParsedPackage(),
  16146.                                     true) . '" optional dependency "' .
  16147.                                 $this->_registry->parsedPackageNameToString(array('package' =>
  16148.                                     $dep['name'], 'channel' => 'pear.php.net'), true) .
  16149.                                 '" will not be automatically downloaded');
  16150.                         }
  16151.                         $skipnames[] = $this->_registry->parsedPackageNameToString($dep, true);
  16152.                         $skip = true;
  16153.                         unset($dep['package']);
  16154.                     }
  16155.                     if (!($ret = $this->_detect2Dep($dep, $pname, 'optional', $params))) {
  16156.                         $dep['package'] = $dep['name'];
  16157.                         $skip = count($skipnames) ?
  16158.                             $skipnames[count($skipnames) - 1] : '';
  16159.                         if ($skip ==
  16160.                               $this->_registry->parsedPackageNameToString($dep, true)) {
  16161.                             array_pop($skipnames);
  16162.                         }
  16163.                     }
  16164.                     if (!$skip && is_array($ret)) {
  16165.                         $this->_downloadDeps[] = $ret;
  16166.                     }
  16167.                 }
  16168.                 if (count($skipnames)) {
  16169.                     if (!isset($options['soft'])) {
  16170.                         $this->_downloader->log(1, 'Did not download optional dependencies: ' .
  16171.                             implode(', ', $skipnames) .
  16172.                             ', use --alldeps to download automatically');
  16173.                     }
  16174.                 }
  16175.             }
  16176.             // get requested dependency group, if any
  16177.             $groupname = $this->getGroup();
  16178.             $explicit = $this->_explicitGroup;
  16179.             if (!$groupname) {
  16180.                 if ($this->canDefault()) {
  16181.                     $groupname = 'default'; // try the default dependency group
  16182.                 } else {
  16183.                     continue;
  16184.                 }
  16185.             }
  16186.             if ($groupnotfound) {
  16187.                 continue;
  16188.             }
  16189.             if (isset($deps['group'])) {
  16190.                 if (isset($deps['group']['attribs'])) {
  16191.                     if (strtolower($deps['group']['attribs']['name']) == strtolower($groupname)) {
  16192.                         $group = $deps['group'];
  16193.                     } elseif ($explicit) {
  16194.                         if (!isset($options['soft'])) {
  16195.                             $this->_downloader->log(0, 'Warning: package "' .
  16196.                                 $this->_registry->parsedPackageNameToString($pname, true) .
  16197.                                 '" has no dependency ' . 'group named "' . $groupname . '"');
  16198.                         }
  16199.                         $groupnotfound = true;
  16200.                         continue;
  16201.                     }
  16202.                 } else {
  16203.                     $found = false;
  16204.                     foreach ($deps['group'] as $group) {
  16205.                         if (strtolower($group['attribs']['name']) == strtolower($groupname)) {
  16206.                             $found = true;
  16207.                             break;
  16208.                         }
  16209.                     }
  16210.                     if (!$found) {
  16211.                         if ($explicit) {
  16212.                             if (!isset($options['soft'])) {
  16213.                                 $this->_downloader->log(0, 'Warning: package "' .
  16214.                                     $this->_registry->parsedPackageNameToString($pname, true) .
  16215.                                     '" has no dependency ' . 'group named "' . $groupname . '"');
  16216.                             }
  16217.                         }
  16218.                         $groupnotfound = true;
  16219.                         continue;
  16220.                     }
  16221.                 }
  16222.             }
  16223.             if (isset($group)) {
  16224.                 if (isset($group[$packagetype])) {
  16225.                     if (isset($group[$packagetype][0])) {
  16226.                         foreach ($group[$packagetype] as $dep) {
  16227.                             $ret = $this->_detect2Dep($dep, $pname, 'dependency group "' .
  16228.                                 $group['attribs']['name'] . '"', $params);
  16229.                             if (is_array($ret)) {
  16230.                                 $this->_downloadDeps[] = $ret;
  16231.                             }
  16232.                         }
  16233.                     } else {
  16234.                         $ret = $this->_detect2Dep($group[$packagetype], $pname,
  16235.                             'dependency group "' .
  16236.                             $group['attribs']['name'] . '"', $params);
  16237.                         if (is_array($ret)) {
  16238.                             $this->_downloadDeps[] = $ret;
  16239.                         }
  16240.                     }
  16241.                 }
  16242.             }
  16243.         }
  16244.     }
  16245.  
  16246.     function _detect2Dep($dep, $pname, $group, $params)
  16247.     {
  16248.         if (isset($dep['conflicts'])) {
  16249.             return true;
  16250.         }
  16251.         $options = $this->_downloader->getOptions();
  16252.         if (isset($dep['uri'])) {
  16253.             return array('uri' => $dep['uri'], 'dep' => $dep);;
  16254.         }
  16255.         $testdep = $dep;
  16256.         $testdep['package'] = $dep['name'];
  16257.         if (PEAR_Downloader_Package::willDownload($testdep, $params)) {
  16258.             $dep['package'] = $dep['name'];
  16259.             if (!isset($options['soft'])) {
  16260.                 $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group .
  16261.                     ' dependency "' .
  16262.                     $this->_registry->parsedPackageNameToString($dep, true) .
  16263.                     '", will be installed');
  16264.             }
  16265.             return false;
  16266.         }
  16267.         $options = $this->_downloader->getOptions();
  16268.         PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  16269.         if ($this->_explicitState) {
  16270.             $pname['state'] = $this->_explicitState;
  16271.         }
  16272.         $url =
  16273.             $this->_downloader->_getDepPackageDownloadUrl($dep, $pname);
  16274.         if (PEAR::isError($url)) {
  16275.             PEAR::popErrorHandling();
  16276.             return $url;
  16277.         }
  16278.         $dep['package'] = $dep['name'];
  16279.         $ret = $this->_analyzeDownloadURL($url, 'dependency', $dep, $params, $group == 'optional' &&
  16280.             !isset($options['alldeps']), true);
  16281.         PEAR::popErrorHandling();
  16282.         if (PEAR::isError($ret)) {
  16283.             if (!isset($options['soft'])) {
  16284.                 $this->_downloader->log(0, $ret->getMessage());
  16285.             }
  16286.             return false;
  16287.         } else {
  16288.             // check to see if a dep is already installed and is the same or newer
  16289.             if (!isset($dep['min']) && !isset($dep['max']) && !isset($dep['recommended'])) {
  16290.                 $oper = 'has';
  16291.             } else {
  16292.                 $oper = 'gt';
  16293.             }
  16294.             // do not try to move this before getDepPackageDownloadURL
  16295.             // we can't determine whether upgrade is necessary until we know what
  16296.             // version would be downloaded
  16297.             if (!isset($options['force']) && $this->isInstalled($ret, $oper)) {
  16298.                 $version = $this->_installRegistry->packageInfo($dep['name'], 'version',
  16299.                     $dep['channel']);
  16300.                 $dep['package'] = $dep['name'];
  16301.                 if (!isset($options['soft'])) {
  16302.                     $this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group .
  16303.                         ' dependency "' .
  16304.                     $this->_registry->parsedPackageNameToString($dep, true) .
  16305.                         '" version ' . $url['version'] . ', already installed as version ' .
  16306.                         $version);
  16307.                 }
  16308.                 return false;
  16309.             }
  16310.         }
  16311.         if (isset($dep['nodefault'])) {
  16312.             $ret['nodefault'] = true;
  16313.         }
  16314.         return $ret;
  16315.     }
  16316.  
  16317.     function _detect1($deps, $pname, $options, $params)
  16318.     {
  16319.         $this->_downloadDeps = array();
  16320.         $skipnames = array();
  16321.         foreach ($deps as $dep) {
  16322.             $nodownload = false;
  16323.             if ($dep['type'] == 'pkg') {
  16324.                 $dep['channel'] = 'pear.php.net';
  16325.                 $dep['package'] = $dep['name'];
  16326.                 switch ($dep['rel']) {
  16327.                     case 'not' :
  16328.                         continue 2;
  16329.                     case 'ge' :
  16330.                     case 'eq' :
  16331.                     case 'gt' :
  16332.                     case 'has' :
  16333.                         $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ?
  16334.                             'required' :
  16335.                             'optional';
  16336.                         if (PEAR_Downloader_Package::willDownload($dep, $params)) {
  16337.                             $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group
  16338.                                 . ' dependency "' .
  16339.                                 $this->_registry->parsedPackageNameToString($dep, true) .
  16340.                                 '", will be installed');
  16341.                             continue 2;
  16342.                         }
  16343.                         $fakedp = new PEAR_PackageFile_v1;
  16344.                         $fakedp->setPackage($dep['name']);
  16345.                         // skip internet check if we are not upgrading (bug #5810)
  16346.                         if (!isset($options['upgrade']) && $this->isInstalled(
  16347.                               $fakedp, $dep['rel'])) {
  16348.                             $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group
  16349.                                 . ' dependency "' .
  16350.                                 $this->_registry->parsedPackageNameToString($dep, true) .
  16351.                                 '", is already installed');
  16352.                             continue 2;
  16353.                         }
  16354.                 }
  16355.                 PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  16356.                 if ($this->_explicitState) {
  16357.                     $pname['state'] = $this->_explicitState;
  16358.                 }
  16359.                 $url =
  16360.                     $this->_downloader->_getDepPackageDownloadUrl($dep, $pname);
  16361.                 $chan = 'pear.php.net';
  16362.                 if (PEAR::isError($url)) {
  16363.                     // check to see if this is a pecl package that has jumped
  16364.                     // from pear.php.net to pecl.php.net channel
  16365.                     if (!class_exists('PEAR_Dependency2')) {
  16366.                         require_once 'phar://go-pear.phar/' . 'PEAR/Dependency2.php';
  16367.                     }
  16368.                     $newdep = PEAR_Dependency2::normalizeDep($dep);
  16369.                     $newdep = $newdep[0];
  16370.                     $newdep['channel'] = 'pecl.php.net';
  16371.                     $chan = 'pecl.php.net';
  16372.                     $url =
  16373.                         $this->_downloader->_getDepPackageDownloadUrl($newdep, $pname);
  16374.                     $obj = &$this->_installRegistry->getPackage($dep['name']);
  16375.                     if (PEAR::isError($url)) {
  16376.                         PEAR::popErrorHandling();
  16377.                         if ($obj !== null && $this->isInstalled($obj, $dep['rel'])) {
  16378.                             $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ?
  16379.                                 'required' :
  16380.                                 'optional';
  16381.                             $dep['package'] = $dep['name'];
  16382.                             if (!isset($options['soft'])) {
  16383.                                 $this->_downloader->log(3, $this->getShortName() .
  16384.                                     ': Skipping ' . $group . ' dependency "' .
  16385.                                     $this->_registry->parsedPackageNameToString($dep, true) .
  16386.                                     '", already installed as version ' . $obj->getVersion());
  16387.                             }
  16388.                             $skip = count($skipnames) ?
  16389.                                 $skipnames[count($skipnames) - 1] : '';
  16390.                             if ($skip ==
  16391.                                   $this->_registry->parsedPackageNameToString($dep, true)) {
  16392.                                 array_pop($skipnames);
  16393.                             }
  16394.                             continue;
  16395.                         } else {
  16396.                             if (isset($dep['optional']) && $dep['optional'] == 'yes') {
  16397.                                 $this->_downloader->log(2, $this->getShortName() .
  16398.                                     ': Skipping optional dependency "' .
  16399.                                     $this->_registry->parsedPackageNameToString($dep, true) .
  16400.                                     '", no releases exist');
  16401.                                 continue;
  16402.                             } else {
  16403.                                 return $url;
  16404.                             }
  16405.                         }
  16406.                     }
  16407.                 }
  16408.                 PEAR::popErrorHandling();
  16409.                 if (!isset($options['alldeps'])) {
  16410.                     if (isset($dep['optional']) && $dep['optional'] == 'yes') {
  16411.                         if (!isset($options['soft'])) {
  16412.                             $this->_downloader->log(3, 'Notice: package "' .
  16413.                                 $this->getShortName() .
  16414.                                 '" optional dependency "' .
  16415.                                 $this->_registry->parsedPackageNameToString(
  16416.                                     array('channel' => $chan, 'package' =>
  16417.                                     $dep['name']), true) .
  16418.                                 '" will not be automatically downloaded');
  16419.                         }
  16420.                         $skipnames[] = $this->_registry->parsedPackageNameToString(
  16421.                                 array('channel' => $chan, 'package' =>
  16422.                                 $dep['name']), true);
  16423.                         $nodownload = true;
  16424.                     }
  16425.                 }
  16426.                 if (!isset($options['alldeps']) && !isset($options['onlyreqdeps'])) {
  16427.                     if (!isset($dep['optional']) || $dep['optional'] == 'no') {
  16428.                         if (!isset($options['soft'])) {
  16429.                             $this->_downloader->log(3, 'Notice: package "' .
  16430.                                 $this->getShortName() .
  16431.                                 '" required dependency "' .
  16432.                                 $this->_registry->parsedPackageNameToString(
  16433.                                     array('channel' => $chan, 'package' =>
  16434.                                     $dep['name']), true) .
  16435.                                 '" will not be automatically downloaded');
  16436.                         }
  16437.                         $skipnames[] = $this->_registry->parsedPackageNameToString(
  16438.                                 array('channel' => $chan, 'package' =>
  16439.                                 $dep['name']), true);
  16440.                         $nodownload = true;
  16441.                     }
  16442.                 }
  16443.                 // check to see if a dep is already installed
  16444.                 // do not try to move this before getDepPackageDownloadURL
  16445.                 // we can't determine whether upgrade is necessary until we know what
  16446.                 // version would be downloaded
  16447.                 if (!isset($options['force']) && $this->isInstalled(
  16448.                         $url, $dep['rel'])) {
  16449.                     $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ?
  16450.                         'required' :
  16451.                         'optional';
  16452.                     $dep['package'] = $dep['name'];
  16453.                     if (isset($newdep)) {
  16454.                         $version = $this->_installRegistry->packageInfo($newdep['name'], 'version',
  16455.                             $newdep['channel']);
  16456.                     } else {
  16457.                         $version = $this->_installRegistry->packageInfo($dep['name'], 'version');
  16458.                     }
  16459.                     $dep['version'] = $url['version'];
  16460.                     if (!isset($options['soft'])) {
  16461.                         $this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group .
  16462.                             ' dependency "' .
  16463.                             $this->_registry->parsedPackageNameToString($dep, true) .
  16464.                             '", already installed as version ' . $version);
  16465.                     }
  16466.                     $skip = count($skipnames) ?
  16467.                         $skipnames[count($skipnames) - 1] : '';
  16468.                     if ($skip ==
  16469.                           $this->_registry->parsedPackageNameToString($dep, true)) {
  16470.                         array_pop($skipnames);
  16471.                     }
  16472.                     continue;
  16473.                 }
  16474.                 if ($nodownload) {
  16475.                     continue;
  16476.                 }
  16477.                 PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  16478.                 if (isset($newdep)) {
  16479.                     $dep = $newdep;
  16480.                 }
  16481.                 $dep['package'] = $dep['name'];
  16482.                 $ret = $this->_analyzeDownloadURL($url, 'dependency', $dep, $params,
  16483.                     isset($dep['optional']) && $dep['optional'] == 'yes' &&
  16484.                     !isset($options['alldeps']), true);
  16485.                 PEAR::popErrorHandling();
  16486.                 if (PEAR::isError($ret)) {
  16487.                     if (!isset($options['soft'])) {
  16488.                         $this->_downloader->log(0, $ret->getMessage());
  16489.                     }
  16490.                     continue;
  16491.                 }
  16492.                 $this->_downloadDeps[] = $ret;
  16493.             }
  16494.         }
  16495.         if (count($skipnames)) {
  16496.             if (!isset($options['soft'])) {
  16497.                 $this->_downloader->log(1, 'Did not download dependencies: ' .
  16498.                     implode(', ', $skipnames) .
  16499.                     ', use --alldeps or --onlyreqdeps to download automatically');
  16500.             }
  16501.         }
  16502.     }
  16503.  
  16504.     function setDownloadURL($pkg)
  16505.     {
  16506.         $this->_downloadURL = $pkg;
  16507.     }
  16508.  
  16509.     /**
  16510.      * Set the package.xml object for this downloaded package
  16511.      *
  16512.      * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 $pkg
  16513.      */
  16514.     function setPackageFile(&$pkg)
  16515.     {
  16516.         $this->_packagefile = &$pkg;
  16517.     }
  16518.  
  16519.     function getShortName()
  16520.     {
  16521.         return $this->_registry->parsedPackageNameToString(array('channel' => $this->getChannel(),
  16522.             'package' => $this->getPackage()), true);
  16523.     }
  16524.  
  16525.     function getParsedPackage()
  16526.     {   
  16527.         if (isset($this->_packagefile) || isset($this->_parsedname)) {
  16528.             return array('channel' => $this->getChannel(),
  16529.                 'package' => $this->getPackage(),
  16530.                 'version' => $this->getVersion());
  16531.         }
  16532.         return false;
  16533.     }
  16534.  
  16535.     function getDownloadURL()
  16536.     {
  16537.         return $this->_downloadURL;
  16538.     }
  16539.  
  16540.     function canDefault()
  16541.     {
  16542.         if (isset($this->_downloadURL)) {
  16543.             if (isset($this->_downloadURL['nodefault'])) {
  16544.                 return false;
  16545.             }
  16546.         }
  16547.         return true;
  16548.     }
  16549.  
  16550.     function getPackage()
  16551.     {
  16552.         if (isset($this->_packagefile)) {
  16553.             return $this->_packagefile->getPackage();
  16554.         } elseif (isset($this->_downloadURL['info'])) {
  16555.             return $this->_downloadURL['info']->getPackage();
  16556.         } else {
  16557.             return false;
  16558.         }
  16559.     }
  16560.  
  16561.     /**
  16562.      * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  16563.      */
  16564.     function isSubpackage(&$pf)
  16565.     {
  16566.         if (isset($this->_packagefile)) {
  16567.             return $this->_packagefile->isSubpackage($pf);
  16568.         } elseif (isset($this->_downloadURL['info'])) {
  16569.             return $this->_downloadURL['info']->isSubpackage($pf);
  16570.         } else {
  16571.             return false;
  16572.         }
  16573.     }
  16574.  
  16575.     function getPackageType()
  16576.     {
  16577.         if (isset($this->_packagefile)) {
  16578.             return $this->_packagefile->getPackageType();
  16579.         } elseif (isset($this->_downloadURL['info'])) {
  16580.             return $this->_downloadURL['info']->getPackageType();
  16581.         } else {
  16582.             return false;
  16583.         }
  16584.     }
  16585.  
  16586.     function isBundle()
  16587.     {
  16588.         if (isset($this->_packagefile)) {
  16589.             return $this->_packagefile->getPackageType() == 'bundle';
  16590.         } else {
  16591.             return false;
  16592.         }
  16593.     }
  16594.  
  16595.     function getPackageXmlVersion()
  16596.     {
  16597.         if (isset($this->_packagefile)) {
  16598.             return $this->_packagefile->getPackagexmlVersion();
  16599.         } elseif (isset($this->_downloadURL['info'])) {
  16600.             return $this->_downloadURL['info']->getPackagexmlVersion();
  16601.         } else {
  16602.             return '1.0';
  16603.         }
  16604.     }
  16605.  
  16606.     function getChannel()
  16607.     {
  16608.         if (isset($this->_packagefile)) {
  16609.             return $this->_packagefile->getChannel();
  16610.         } elseif (isset($this->_downloadURL['info'])) {
  16611.             return $this->_downloadURL['info']->getChannel();
  16612.         } else {
  16613.             return false;
  16614.         }
  16615.     }
  16616.  
  16617.     function getURI()
  16618.     {
  16619.         if (isset($this->_packagefile)) {
  16620.             return $this->_packagefile->getURI();
  16621.         } elseif (isset($this->_downloadURL['info'])) {
  16622.             return $this->_downloadURL['info']->getURI();
  16623.         } else {
  16624.             return false;
  16625.         }
  16626.     }
  16627.  
  16628.     function getVersion()
  16629.     {
  16630.         if (isset($this->_packagefile)) {
  16631.             return $this->_packagefile->getVersion();
  16632.         } elseif (isset($this->_downloadURL['version'])) {
  16633.             return $this->_downloadURL['version'];
  16634.         } else {
  16635.             return false;
  16636.         }
  16637.     }
  16638.  
  16639.     function isCompatible($pf)
  16640.     {
  16641.         if (isset($this->_packagefile)) {
  16642.             return $this->_packagefile->isCompatible($pf);
  16643.         } elseif (isset($this->_downloadURL['info'])) {
  16644.             return $this->_downloadURL['info']->isCompatible($pf);
  16645.         } else {
  16646.             return true;
  16647.         }
  16648.     }
  16649.  
  16650.     function setGroup($group)
  16651.     {
  16652.         $this->_parsedname['group'] = $group;
  16653.     }
  16654.  
  16655.     function getGroup()
  16656.     {
  16657.         if (isset($this->_parsedname['group'])) {
  16658.             return $this->_parsedname['group'];
  16659.         } else {
  16660.             return '';
  16661.         }
  16662.     }
  16663.  
  16664.     function isExtension($name)
  16665.     {
  16666.         if (isset($this->_packagefile)) {
  16667.             return $this->_packagefile->isExtension($name);
  16668.         } elseif (isset($this->_downloadURL['info'])) {
  16669.             if ($this->_downloadURL['info']->getPackagexmlVersion() == '2.0') {
  16670.                 return $this->_downloadURL['info']->getProvidesExtension() == $name;
  16671.             } else {
  16672.                 return false;
  16673.             }
  16674.         } else {
  16675.             return false;
  16676.         }
  16677.     }
  16678.  
  16679.     function getDeps()
  16680.     {
  16681.         if (isset($this->_packagefile)) {
  16682.             $ver = $this->_packagefile->getPackagexmlVersion();
  16683.             if (version_compare($ver, '2.0', '>=')) {
  16684.                 return $this->_packagefile->getDeps(true);
  16685.             } else {
  16686.                 return $this->_packagefile->getDeps();
  16687.             }
  16688.         } elseif (isset($this->_downloadURL['info'])) {
  16689.             $ver = $this->_downloadURL['info']->getPackagexmlVersion();
  16690.             if (version_compare($ver, '2.0', '>=')) {
  16691.                 return $this->_downloadURL['info']->getDeps(true);
  16692.             } else {
  16693.                 return $this->_downloadURL['info']->getDeps();
  16694.             }
  16695.         } else {
  16696.             return array();
  16697.         }
  16698.     }
  16699.  
  16700.     /**
  16701.      * @param array Parsed array from {@link PEAR_Registry::parsePackageName()} or a dependency
  16702.      *                     returned from getDepDownloadURL()
  16703.      */
  16704.     function isEqual($param)
  16705.     {
  16706.         if (is_object($param)) {
  16707.             $channel = $param->getChannel();
  16708.             $package = $param->getPackage();
  16709.             if ($param->getURI()) {
  16710.                 $param = array(
  16711.                     'channel' => $param->getChannel(),
  16712.                     'package' => $param->getPackage(),
  16713.                     'version' => $param->getVersion(),
  16714.                     'uri' => $param->getURI(),
  16715.                 );
  16716.             } else {
  16717.                 $param = array(
  16718.                     'channel' => $param->getChannel(),
  16719.                     'package' => $param->getPackage(),
  16720.                     'version' => $param->getVersion(),
  16721.                 );
  16722.             }
  16723.         } else {
  16724.             if (isset($param['uri'])) {
  16725.                 if ($this->getChannel() != '__uri') {
  16726.                     return false;
  16727.                 }
  16728.                 return $param['uri'] == $this->getURI();
  16729.             }
  16730.             $package = isset($param['package']) ? $param['package'] :
  16731.                 $param['info']->getPackage();
  16732.             $channel = isset($param['channel']) ? $param['channel'] :
  16733.                 $param['info']->getChannel();
  16734.             if (isset($param['rel'])) {
  16735.                 if (!class_exists('PEAR_Dependency2')) {
  16736.                     require_once 'phar://go-pear.phar/' . 'PEAR/Dependency2.php';
  16737.                 }
  16738.                 $newdep = PEAR_Dependency2::normalizeDep($param);
  16739.                 $newdep = $newdep[0];
  16740.             } elseif (isset($param['min'])) {
  16741.                 $newdep = $param;
  16742.             }
  16743.         }
  16744.         if (isset($newdep)) {
  16745.             if (!isset($newdep['min'])) {
  16746.                 $newdep['min'] = '0';
  16747.             }
  16748.             if (!isset($newdep['max'])) {
  16749.                 $newdep['max'] = '100000000000000000000';
  16750.             }
  16751.             // use magic to support pecl packages suddenly jumping to the pecl channel
  16752.             // we need to support both dependency possibilities
  16753.             if ($channel == 'pear.php.net' && $this->getChannel() == 'pecl.php.net') {
  16754.                 if ($package == $this->getPackage()) {
  16755.                     $channel = 'pecl.php.net';
  16756.                 }
  16757.             }
  16758.             if ($channel == 'pecl.php.net' && $this->getChannel() == 'pear.php.net') {
  16759.                 if ($package == $this->getPackage()) {
  16760.                     $channel = 'pear.php.net';
  16761.                 }
  16762.             }
  16763.             return (strtolower($package) == strtolower($this->getPackage()) &&
  16764.                 $channel == $this->getChannel() &&
  16765.                 version_compare($newdep['min'], $this->getVersion(), '<=') &&
  16766.                 version_compare($newdep['max'], $this->getVersion(), '>='));
  16767.         }
  16768.         // use magic to support pecl packages suddenly jumping to the pecl channel
  16769.         if ($channel == 'pecl.php.net' && $this->getChannel() == 'pear.php.net') {
  16770.             if (strtolower($package) == strtolower($this->getPackage())) {
  16771.                 $channel = 'pear.php.net';
  16772.             }
  16773.         }
  16774.         if (isset($param['version'])) {
  16775.             return (strtolower($package) == strtolower($this->getPackage()) &&
  16776.                 $channel == $this->getChannel() &&
  16777.                 $param['version'] == $this->getVersion());
  16778.         } else {
  16779.             return strtolower($package) == strtolower($this->getPackage()) &&
  16780.                 $channel == $this->getChannel();
  16781.         }
  16782.     }
  16783.  
  16784.     function isInstalled($dep, $oper = '==')
  16785.     {
  16786.         if (!$dep) {
  16787.             return false;
  16788.         }
  16789.         if ($oper != 'ge' && $oper != 'gt' && $oper != 'has' && $oper != '==') {
  16790.             return false;
  16791.         }
  16792.         if (is_object($dep)) {
  16793.             $package = $dep->getPackage();
  16794.             $channel = $dep->getChannel();
  16795.             if ($dep->getURI()) {
  16796.                 $dep = array(
  16797.                     'uri' => $dep->getURI(),
  16798.                     'version' => $dep->getVersion(),
  16799.                 );
  16800.             } else {
  16801.                 $dep = array(
  16802.                     'version' => $dep->getVersion(),
  16803.                 );
  16804.             }
  16805.         } else {
  16806.             if (isset($dep['uri'])) {
  16807.                 $channel = '__uri';
  16808.                 $package = $dep['dep']['name'];
  16809.             } else {
  16810.                 $channel = $dep['info']->getChannel();
  16811.                 $package = $dep['info']->getPackage();
  16812.             }
  16813.         }
  16814.         $options = $this->_downloader->getOptions();
  16815.         $test = $this->_installRegistry->packageExists($package, $channel);
  16816.         if (!$test && $channel == 'pecl.php.net') {
  16817.             // do magic to allow upgrading from old pecl packages to new ones
  16818.             $test = $this->_installRegistry->packageExists($package, 'pear.php.net');
  16819.             $channel = 'pear.php.net';
  16820.         }
  16821.         if ($test) {
  16822.             if (isset($dep['uri'])) {
  16823.                 if ($this->_installRegistry->packageInfo($package, 'uri', '__uri') == $dep['uri']) {
  16824.                     return true;
  16825.                 }
  16826.             }
  16827.             if (isset($options['upgrade'])) {
  16828.                 if ($oper == 'has') {
  16829.                     if (version_compare($this->_installRegistry->packageInfo(
  16830.                           $package, 'version', $channel),
  16831.                           $dep['version'], '>=')) {
  16832.                         return true;
  16833.                     } else {
  16834.                         return false;
  16835.                     }
  16836.                 } else {
  16837.                     if (version_compare($this->_installRegistry->packageInfo(
  16838.                           $package, 'version', $channel),
  16839.                           $dep['version'], '>=')) {
  16840.                         return true;
  16841.                     }
  16842.                     return false;
  16843.                 }
  16844.             }
  16845.             return true;
  16846.         }
  16847.         return false;
  16848.     }
  16849.  
  16850.     /**
  16851.      * Detect duplicate package names with differing versions
  16852.      * 
  16853.      * If a user requests to install Date 1.4.6 and Date 1.4.7,
  16854.      * for instance, this is a logic error.  This method
  16855.      * detects this situation.
  16856.      *
  16857.      * @param array $params array of PEAR_Downloader_Package objects
  16858.      * @param array $errorparams empty array
  16859.      * @return array array of stupid duplicated packages in PEAR_Downloader_Package obejcts
  16860.      */
  16861.     function detectStupidDuplicates($params, &$errorparams)
  16862.     {
  16863.         $existing = array();
  16864.         foreach ($params as $i => $param) {
  16865.             if (!isset($existing[$param->getChannel() . '/' . $param->getPackage()])) {
  16866.                 $existing[$param->getChannel() . '/' . $param->getPackage()] = array();
  16867.             }
  16868.             if (!isset($existing[$param->getChannel() . '/' . $param->getPackage()]
  16869.                 [$param->getGroup()])) {
  16870.                 $existing[$param->getChannel() . '/' . $param->getPackage()]
  16871.                     [$param->getGroup()] = array();
  16872.             }
  16873.             $existing[$param->getChannel() . '/' . $param->getPackage()]
  16874.                 [$param->getGroup()][] = $i;
  16875.         }
  16876.         $indices = array();
  16877.         foreach ($existing as $package => $groups) {
  16878.             foreach ($groups as $group => $dupes) {
  16879.                 if (count($dupes) > 1) {
  16880.                     $indices = $indices + $dupes;
  16881.                 }
  16882.             }
  16883.         }
  16884.         $indices = array_unique($indices);
  16885.         foreach ($indices as $index) {
  16886.             $errorparams[] = $params[$index];
  16887.         }
  16888.         return count($errorparams);
  16889.     }
  16890.  
  16891.     /**
  16892.      * @param array
  16893.      * @param bool ignore install groups - for final removal of dupe packages
  16894.      * @static
  16895.      */
  16896.     function removeDuplicates(&$params, $ignoreGroups = false)
  16897.     {
  16898.         $pnames = array();
  16899.         foreach ($params as $i => $param) {
  16900.             if (!$param) {
  16901.                 continue;
  16902.             }
  16903.             if ($param->getPackage()) {
  16904.                 if ($ignoreGroups) {
  16905.                     $group = '';
  16906.                 } else {
  16907.                     $group = $param->getGroup();
  16908.                 }
  16909.                 $pnames[$i] = $param->getChannel() . '/' .
  16910.                     $param->getPackage() . '-' . $param->getVersion() . '#' . $group;
  16911.             }
  16912.         }
  16913.         $pnames = array_unique($pnames);
  16914.         $unset = array_diff(array_keys($params), array_keys($pnames));
  16915.         $testp = array_flip($pnames);
  16916.         foreach ($params as $i => $param) {
  16917.             if (!$param) {
  16918.                 $unset[] = $i;
  16919.                 continue;
  16920.             }
  16921.             if (!is_a($param, 'PEAR_Downloader_Package')) {
  16922.                 $unset[] = $i;
  16923.                 continue;
  16924.             }
  16925.             if ($ignoreGroups) {
  16926.                 $group = '';
  16927.             } else {
  16928.                 $group = $param->getGroup();
  16929.             }
  16930.             if (!isset($testp[$param->getChannel() . '/' . $param->getPackage() . '-' .
  16931.                   $param->getVersion() . '#' . $group])) {
  16932.                 $unset[] = $i;
  16933.             }
  16934.         }
  16935.         foreach ($unset as $i) {
  16936.             unset($params[$i]);
  16937.         }
  16938.         $ret = array();
  16939.         foreach ($params as $i => $param) {
  16940.             $ret[] = &$params[$i];
  16941.         }
  16942.         $params = array();
  16943.         foreach ($ret as $i => $param) {
  16944.             $params[] = &$ret[$i];
  16945.         }
  16946.     }
  16947.  
  16948.     function explicitState()
  16949.     {
  16950.         return $this->_explicitState;
  16951.     }
  16952.  
  16953.     function setExplicitState($s)
  16954.     {
  16955.         $this->_explicitState = $s;
  16956.     }
  16957.  
  16958.     /**
  16959.      * @static
  16960.      */
  16961.     function mergeDependencies(&$params)
  16962.     {
  16963.         $newparams = array();
  16964.         $bundles = array();
  16965.         foreach ($params as $i => $param) {
  16966.             if (!$param->isBundle()) {
  16967.                 continue;
  16968.             }
  16969.             $bundles[] = $i;
  16970.             $pf = &$param->getPackageFile();
  16971.             $newdeps = array();
  16972.             $contents = $pf->getBundledPackages();
  16973.             if (!is_array($contents)) {
  16974.                 $contents = array($contents);
  16975.             }
  16976.             foreach ($contents as $file) {
  16977.                 $filecontents = $pf->getFileContents($file);
  16978.                 $dl = &$param->getDownloader();
  16979.                 $options = $dl->getOptions();
  16980.                 if (PEAR::isError($dir = $dl->getDownloadDir())) {
  16981.                     return $dir;
  16982.                 }
  16983.                 $fp = @fopen($dir . DIRECTORY_SEPARATOR . $file, 'wb');
  16984.                 if (!$fp) {
  16985.                     continue;
  16986.                 }
  16987.                 fwrite($fp, $filecontents, strlen($filecontents));
  16988.                 fclose($fp);
  16989.                 if ($s = $params[$i]->explicitState()) {
  16990.                     $obj->setExplicitState($s);
  16991.                 }
  16992.                 $obj = &new PEAR_Downloader_Package($params[$i]->getDownloader());
  16993.                 PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  16994.                 if (PEAR::isError($dir = $dl->getDownloadDir())) {
  16995.                     PEAR::popErrorHandling();
  16996.                     return $dir;
  16997.                 }
  16998.                 $e = $obj->_fromFile($a = $dir . DIRECTORY_SEPARATOR . $file);
  16999.                 PEAR::popErrorHandling();
  17000.                 if (PEAR::isError($e)) {
  17001.                     if (!isset($options['soft'])) {
  17002.                         $dl->log(0, $e->getMessage());
  17003.                     }
  17004.                     continue;
  17005.                 }
  17006.                 $j = &$obj;
  17007.                 if (!PEAR_Downloader_Package::willDownload($j,
  17008.                       array_merge($params, $newparams)) && !$param->isInstalled($j)) {
  17009.                     $newparams[] = &$j;
  17010.                 }
  17011.             }
  17012.         }
  17013.         foreach ($bundles as $i) {
  17014.             unset($params[$i]); // remove bundles - only their contents matter for installation
  17015.         }
  17016.         PEAR_Downloader_Package::removeDuplicates($params); // strip any unset indices
  17017.         if (count($newparams)) { // add in bundled packages for install
  17018.             foreach ($newparams as $i => $unused) {
  17019.                 $params[] = &$newparams[$i];
  17020.             }
  17021.             $newparams = array();
  17022.         }
  17023.         foreach ($params as $i => $param) {
  17024.             $newdeps = array();
  17025.             foreach ($param->_downloadDeps as $dep) {
  17026.                 if (!PEAR_Downloader_Package::willDownload($dep,
  17027.                       array_merge($params, $newparams)) && !$param->isInstalled($dep)) {
  17028.                     $newdeps[] = $dep;
  17029.                 } else {
  17030.                     // detect versioning conflicts here
  17031.                 }
  17032.             }
  17033.             // convert the dependencies into PEAR_Downloader_Package objects for the next time
  17034.             // around
  17035.             $params[$i]->_downloadDeps = array();
  17036.             foreach ($newdeps as $dep) {
  17037.                 $obj = &new PEAR_Downloader_Package($params[$i]->getDownloader());
  17038.                 if ($s = $params[$i]->explicitState()) {
  17039.                     $obj->setExplicitState($s);
  17040.                 }
  17041.                 PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  17042.                 $e = $obj->fromDepURL($dep);
  17043.                 PEAR::popErrorHandling();
  17044.                 if (PEAR::isError($e)) {
  17045.                     if (!isset($options['soft'])) {
  17046.                         $obj->_downloader->log(0, $e->getMessage());
  17047.                     }
  17048.                     continue;
  17049.                 }
  17050.                 $e = $obj->detectDependencies($params);
  17051.                 if (PEAR::isError($e)) {
  17052.                     if (!isset($options['soft'])) {
  17053.                         $obj->_downloader->log(0, $e->getMessage());
  17054.                     }
  17055.                 }
  17056.                 $j = &$obj;
  17057.                 $newparams[] = &$j;
  17058.             }
  17059.         }
  17060.         if (count($newparams)) {
  17061.             foreach ($newparams as $i => $unused) {
  17062.                 $params[] = &$newparams[$i];
  17063.             }
  17064.             return true;
  17065.         } else {
  17066.             return false;
  17067.         }
  17068.     }
  17069.  
  17070.  
  17071.     /**
  17072.      * @static
  17073.      */
  17074.     function willDownload($param, $params)
  17075.     {
  17076.         if (!is_array($params)) {
  17077.             return false;
  17078.         }
  17079.         foreach ($params as $obj) {
  17080.             if ($obj->isEqual($param)) {
  17081.                 return true;
  17082.             }
  17083.         }
  17084.         return false;
  17085.     }
  17086.  
  17087.     /**
  17088.      * For simpler unit-testing
  17089.      * @param PEAR_Config
  17090.      * @param int
  17091.      * @param string
  17092.      */
  17093.     function &getPackagefileObject(&$c, $d, $t = false)
  17094.     {
  17095.         $a = &new PEAR_PackageFile($c, $d, $t);
  17096.         return $a;
  17097.     }
  17098.  
  17099.  
  17100.     /**
  17101.      * This will retrieve from a local file if possible, and parse out
  17102.      * a group name as well.  The original parameter will be modified to reflect this.
  17103.      * @param string|array can be a parsed package name as well
  17104.      * @access private
  17105.      */
  17106.     function _fromFile(&$param)
  17107.     {
  17108.         $saveparam = $param;
  17109.         if (is_string($param)) {
  17110.             if (!@file_exists($param)) {
  17111.                 $test = explode('#', $param);
  17112.                 $group = array_pop($test);
  17113.                 if (@file_exists(implode('#', $test))) {
  17114.                     $this->setGroup($group);
  17115.                     $param = implode('#', $test);
  17116.                     $this->_explicitGroup = true;
  17117.                 }
  17118.             }
  17119.             if (@is_file($param)) {
  17120.                 $this->_type = 'local';
  17121.                 $options = $this->_downloader->getOptions();
  17122.                 if (isset($options['downloadonly'])) {
  17123.                     $pkg = &$this->getPackagefileObject($this->_config,
  17124.                         $this->_downloader->_debug);
  17125.                 } else {
  17126.                     if (PEAR::isError($dir = $this->_downloader->getDownloadDir())) {
  17127.                         return $dir;
  17128.                     }
  17129.                     $pkg = &$this->getPackagefileObject($this->_config,
  17130.                         $this->_downloader->_debug, $dir);
  17131.                 }
  17132.                 PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  17133.                 $pf = &$pkg->fromAnyFile($param, PEAR_VALIDATE_INSTALLING);
  17134.                 PEAR::popErrorHandling();
  17135.                 if (PEAR::isError($pf)) {
  17136.                     $this->_valid = false;
  17137.                     $param = $saveparam;
  17138.                     return $pf;
  17139.                 }
  17140.                 $this->_packagefile = &$pf;
  17141.                 if (!$this->getGroup()) {
  17142.                     $this->setGroup('default'); // install the default dependency group
  17143.                 }
  17144.                 return $this->_valid = true;
  17145.             }
  17146.         }
  17147.         $param = $saveparam;
  17148.         return $this->_valid = false;
  17149.     }
  17150.  
  17151.     function _fromUrl($param, $saveparam = '')
  17152.     {
  17153.         if (!is_array($param) &&
  17154.               (preg_match('#^(http|ftp)://#', $param))) {
  17155.             $options = $this->_downloader->getOptions();
  17156.             $this->_type = 'url';
  17157.             $callback = $this->_downloader->ui ?
  17158.                 array(&$this->_downloader, '_downloadCallback') : null;
  17159.             $this->_downloader->pushErrorHandling(PEAR_ERROR_RETURN);
  17160.             if (PEAR::isError($dir = $this->_downloader->getDownloadDir())) {
  17161.                 $this->_downloader->popErrorHandling();
  17162.                 return $dir;
  17163.             }
  17164.             $this->_downloader->log(3, 'Downloading "' . $param . '"');
  17165.             $file = $this->_downloader->downloadHttp($param, $this->_downloader->ui,
  17166.                 $dir, $callback, null, false, $this->getChannel());
  17167.             $this->_downloader->popErrorHandling();
  17168.             if (PEAR::isError($file)) {
  17169.                 if (!empty($saveparam)) {
  17170.                     $saveparam = ", cannot download \"$saveparam\"";
  17171.                 }
  17172.                 $err = PEAR::raiseError('Could not download from "' . $param .
  17173.                     '"' . $saveparam . ' (' . $file->getMessage() . ')');
  17174.                     return $err;
  17175.             }
  17176.             if ($this->_rawpackagefile) {
  17177.                 require_once 'phar://go-pear.phar/' . 'Archive/Tar.php';
  17178.                 $tar = &new Archive_Tar($file);
  17179.                 $packagexml = $tar->extractInString('package2.xml');
  17180.                 if (!$packagexml) {
  17181.                     $packagexml = $tar->extractInString('package.xml');
  17182.                 }
  17183.                 if (str_replace(array("\n", "\r"), array('',''), $packagexml) !=
  17184.                       str_replace(array("\n", "\r"), array('',''), $this->_rawpackagefile)) {
  17185.                     if ($this->getChannel() == 'pear.php.net') {
  17186.                         // be more lax for the existing PEAR packages that have not-ok
  17187.                         // characters in their package.xml
  17188.                         $this->_downloader->log(0, 'CRITICAL WARNING: The "' .
  17189.                             $this->getPackage() . '" package has invalid characters in its ' .
  17190.                             'package.xml.  The next version of PEAR may not be able to install ' .
  17191.                             'this package for security reasons.  Please open a bug report at ' .
  17192.                             'http://pear.php.net/package/' . $this->getPackage() . '/bugs');
  17193.                     } else {
  17194.                         return PEAR::raiseError('CRITICAL ERROR: package.xml downloaded does ' .
  17195.                             'not match value returned from xml-rpc');
  17196.                     }
  17197.                 }
  17198.             }
  17199.             // whew, download worked!
  17200.             if (isset($options['downloadonly'])) {
  17201.                 $pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->debug);
  17202.             } else {
  17203.                 if (PEAR::isError($dir = $this->_downloader->getDownloadDir())) {
  17204.                     return $dir;
  17205.                 }
  17206.                 $pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->debug,
  17207.                     $dir);
  17208.             }
  17209.             PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  17210.             $pf = &$pkg->fromAnyFile($file, PEAR_VALIDATE_INSTALLING);
  17211.             PEAR::popErrorHandling();
  17212.             if (PEAR::isError($pf)) {
  17213.                 if (is_array($pf->getUserInfo())) {
  17214.                     foreach ($pf->getUserInfo() as $err) {
  17215.                         if (is_array($err)) {
  17216.                             $err = $err['message'];
  17217.                         }
  17218.                         if (!isset($options['soft'])) {
  17219.                             $this->_downloader->log(0, "Validation Error: $err");
  17220.                         }
  17221.                     }
  17222.                 }
  17223.                 if (!isset($options['soft'])) {
  17224.                     $this->_downloader->log(0, $pf->getMessage());
  17225.                 }
  17226.                 $err = PEAR::raiseError('Download of "' . ($saveparam ? $saveparam :
  17227.                     $param) . '" succeeded, but it is not a valid package archive');
  17228.                 $this->_valid = false;
  17229.                 return $err;
  17230.             }
  17231.             $this->_packagefile = &$pf;
  17232.             $this->setGroup('default'); // install the default dependency group
  17233.             return $this->_valid = true;
  17234.         }
  17235.         return $this->_valid = false;
  17236.     }
  17237.  
  17238.     /**
  17239.      *
  17240.      * @param string|array pass in an array of format
  17241.      *                     array(
  17242.      *                      'package' => 'pname',
  17243.      *                     ['channel' => 'channame',]
  17244.      *                     ['version' => 'version',]
  17245.      *                     ['state' => 'state',])
  17246.      *                     or a string of format [channame/]pname[-version|-state]
  17247.      */
  17248.     function _fromString($param)
  17249.     {
  17250.         $options = $this->_downloader->getOptions();
  17251.         PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  17252.         $pname = $this->_registry->parsePackageName($param,
  17253.             $this->_config->get('default_channel'));
  17254.         PEAR::popErrorHandling();
  17255.         if (PEAR::isError($pname)) {
  17256.             if ($pname->getCode() == 'invalid') {
  17257.                 $this->_valid = false;
  17258.                 return false;
  17259.             }
  17260.             if ($pname->getCode() == 'channel') {
  17261.                 $parsed = $pname->getUserInfo();
  17262.                 if ($this->_downloader->discover($parsed['channel'])) {
  17263.                     if ($this->_config->get('auto_discover')) {
  17264.                         PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  17265.                         $pname = $this->_registry->parsePackageName($param,
  17266.                             $this->_config->get('default_channel'));
  17267.                         PEAR::popErrorHandling();
  17268.                     } else {
  17269.                         if (!isset($options['soft'])) {
  17270.                             $this->_downloader->log(0, 'Channel "' . $parsed['channel'] .
  17271.                                 '" is not initialized, use ' .
  17272.                                 '"pear channel-discover ' . $parsed['channel'] . '" to initialize' .
  17273.                                 'or pear config-set auto_discover 1');
  17274.                         }
  17275.                     }
  17276.                 }
  17277.                 if (PEAR::isError($pname)) {
  17278.                     if (!isset($options['soft'])) {
  17279.                         $this->_downloader->log(0, $pname->getMessage());
  17280.                     }
  17281.                     if (is_array($param)) {
  17282.                         $param = $this->_registry->parsedPackageNameToString($param);
  17283.                     }
  17284.                     $err = PEAR::raiseError('invalid package name/package file "' .
  17285.                         $param . '"');
  17286.                     $this->_valid = false;
  17287.                     return $err;
  17288.                 }
  17289.             } else {
  17290.                 if (!isset($options['soft'])) {
  17291.                     $this->_downloader->log(0, $pname->getMessage());
  17292.                 }
  17293.                 $err = PEAR::raiseError('invalid package name/package file "' .
  17294.                     $param . '"');
  17295.                 $this->_valid = false;
  17296.                 return $err;
  17297.             }
  17298.         }
  17299.         if (!isset($this->_type)) {
  17300.             $this->_type = 'xmlrpc';
  17301.         }
  17302.         $this->_parsedname = $pname;
  17303.         if (isset($pname['state'])) {
  17304.             $this->_explicitState = $pname['state'];
  17305.         } else {
  17306.             $this->_explicitState = false;
  17307.         }
  17308.         if (isset($pname['group'])) {
  17309.             $this->_explicitGroup = true;
  17310.         } else {
  17311.             $this->_explicitGroup = false;
  17312.         }
  17313.         $info = $this->_downloader->_getPackageDownloadUrl($pname);
  17314.         if (PEAR::isError($info)) {
  17315.             if ($info->getCode() != -976 && $pname['channel'] == 'pear.php.net') {
  17316.                 // try pecl
  17317.                 $pname['channel'] = 'pecl.php.net';
  17318.                 if ($test = $this->_downloader->_getPackageDownloadUrl($pname)) {
  17319.                     if (!PEAR::isError($test)) {
  17320.                         $info = PEAR::raiseError($info->getMessage() . ' - package ' .
  17321.                             $this->_registry->parsedPackageNameToString($pname, true) .
  17322.                             ' can be installed with "pecl install ' . $pname['package'] .
  17323.                             '"');
  17324.                     } else {
  17325.                         $pname['channel'] = 'pear.php.net';
  17326.                     }
  17327.                 } else {
  17328.                     $pname['channel'] = 'pear.php.net';
  17329.                 }
  17330.             }
  17331.             return $info;
  17332.         }
  17333.         $this->_rawpackagefile = $info['raw'];
  17334.         $ret = $this->_analyzeDownloadURL($info, $param, $pname);
  17335.         if (PEAR::isError($ret)) {
  17336.             return $ret;
  17337.         }
  17338.         if ($ret) {
  17339.             $this->_downloadURL = $ret;
  17340.             return $this->_valid = (bool) $ret;
  17341.         }
  17342.     }
  17343.  
  17344.     /**
  17345.      * @param array output of package.getDownloadURL
  17346.      * @param string|array|object information for detecting packages to be downloaded, and
  17347.      *                            for errors
  17348.      * @param array name information of the package
  17349.      * @param array|null packages to be downloaded
  17350.      * @param bool is this an optional dependency?
  17351.      * @param bool is this any kind of dependency?
  17352.      * @access private
  17353.      */
  17354.     function _analyzeDownloadURL($info, $param, $pname, $params = null, $optional = false,
  17355.                                  $isdependency = false)
  17356.     {
  17357.         if (!is_string($param) && PEAR_Downloader_Package::willDownload($param, $params)) {
  17358.             return false;
  17359.         }
  17360.         if (!$info) {
  17361.             if (!is_string($param)) {
  17362.                 $saveparam = ", cannot download \"$param\"";
  17363.             } else {
  17364.                 $saveparam = '';
  17365.             }
  17366.             // no releases exist
  17367.             return PEAR::raiseError('No releases for package "' .
  17368.                 $this->_registry->parsedPackageNameToString($pname, true) . '" exist' . $saveparam);
  17369.         }
  17370.         if (strtolower($info['info']->getChannel()) != strtolower($pname['channel'])) {
  17371.             $err = false;
  17372.             if ($pname['channel'] == 'pecl.php.net') {
  17373.                 if ($info['info']->getChannel() != 'pear.php.net') {
  17374.                     $err = true;
  17375.                 }
  17376.             } elseif ($info['info']->getChannel() == 'pecl.php.net') {
  17377.                 if ($pname['channel'] != 'pear.php.net') {
  17378.                     $err = true;
  17379.                 }
  17380.             } else {
  17381.                 $err = true;
  17382.             }
  17383.             if ($err) {
  17384.                 return PEAR::raiseError('SECURITY ERROR: package in channel "' . $pname['channel'] .
  17385.                     '" retrieved another channel\'s name for download! ("' .
  17386.                     $info['info']->getChannel() . '")');
  17387.             }
  17388.         }
  17389.         if (!isset($info['url'])) {
  17390.             if ($this->isInstalled($info)) {
  17391.                 if ($isdependency && version_compare($info['version'],
  17392.                       $this->_registry->packageInfo($info['info']->getPackage(),
  17393.                             'version', $info['info']->getChannel()), '<=')) {
  17394.                     // ignore bogus errors of "failed to download dependency"
  17395.                     // if it is already installed and the one that would be
  17396.                     // downloaded is older or the same version (Bug #7219)
  17397.                     return false;
  17398.                 }
  17399.             }
  17400.             $instead =  ', will instead download version ' . $info['version'] .
  17401.                         ', stability "' . $info['info']->getState() . '"';
  17402.             // releases exist, but we failed to get any
  17403.             if (isset($this->_downloader->_options['force'])) {
  17404.                 if (isset($pname['version'])) {
  17405.                     $vs = ', version "' . $pname['version'] . '"';
  17406.                 } elseif (isset($pname['state'])) {
  17407.                     $vs = ', stability "' . $pname['state'] . '"';
  17408.                 } elseif ($param == 'dependency') {
  17409.                     if (!class_exists('PEAR_Common')) {
  17410.                         require_once 'phar://go-pear.phar/' . 'PEAR/Common.php';
  17411.                     }
  17412.                     if (!in_array($info['info']->getState(),
  17413.                           PEAR_Common::betterStates($this->_config->get('preferred_state'), true))) {
  17414.                         if ($optional) {
  17415.                             // don't spit out confusing error message
  17416.                             return $this->_downloader->_getPackageDownloadUrl(
  17417.                                 array('package' => $pname['package'],
  17418.                                       'channel' => $pname['channel'],
  17419.                                       'version' => $info['version']));
  17420.                         }
  17421.                         $vs = ' within preferred state "' . $this->_config->get('preferred_state') .
  17422.                             '"';
  17423.                     } else {
  17424.                         if (!class_exists('PEAR_Dependency2')) {
  17425.                             require_once 'phar://go-pear.phar/' . 'PEAR/Dependency2.php';
  17426.                         }
  17427.                         if ($optional) {
  17428.                             // don't spit out confusing error message
  17429.                             return $this->_downloader->_getPackageDownloadUrl(
  17430.                                 array('package' => $pname['package'],
  17431.                                       'channel' => $pname['channel'],
  17432.                                       'version' => $info['version']));
  17433.                         }
  17434.                         $vs = PEAR_Dependency2::_getExtraString($pname);
  17435.                         $instead = '';
  17436.                     }
  17437.                 } else {
  17438.                     $vs = ' within preferred state "' . $this->_config->get(
  17439.                         'preferred_state') . '"';
  17440.                 }
  17441.                 if (!isset($options['soft'])) {
  17442.                     $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] .
  17443.                         '/' . $pname['package'] . $vs . $instead);
  17444.                 }
  17445.                 // download the latest release
  17446.                 return $this->_downloader->_getPackageDownloadUrl(
  17447.                     array('package' => $pname['package'],
  17448.                           'channel' => $pname['channel'],
  17449.                           'version' => $info['version']));
  17450.             } else {
  17451.                 if (isset($info['php']) && $info['php']) {
  17452.                     $err = PEAR::raiseError('Failed to download ' .
  17453.                         $this->_registry->parsedPackageNameToString(
  17454.                             array('channel' => $pname['channel'],
  17455.                                   'package' => $pname['package']),
  17456.                                 true) .
  17457.                         ', latest release is version ' . $info['php']['v'] .
  17458.                         ', but it requires PHP version "' .
  17459.                         $info['php']['m'] . '", use "' .
  17460.                         $this->_registry->parsedPackageNameToString(
  17461.                             array('channel' => $pname['channel'], 'package' => $pname['package'],
  17462.                             'version' => $info['php']['v'])) . '" to install',
  17463.                             PEAR_DOWNLOADER_PACKAGE_PHPVERSION);
  17464.                     return $err;
  17465.                 }
  17466.                 // construct helpful error message
  17467.                 if (isset($pname['version'])) {
  17468.                     $vs = ', version "' . $pname['version'] . '"';
  17469.                 } elseif (isset($pname['state'])) {
  17470.                     $vs = ', stability "' . $pname['state'] . '"';
  17471.                 } elseif ($param == 'dependency') {
  17472.                     if (!class_exists('PEAR_Common')) {
  17473.                         require_once 'phar://go-pear.phar/' . 'PEAR/Common.php';
  17474.                     }
  17475.                     if (!in_array($info['info']->getState(),
  17476.                           PEAR_Common::betterStates($this->_config->get('preferred_state'), true))) {
  17477.                         if ($optional) {
  17478.                             // don't spit out confusing error message, and don't die on
  17479.                             // optional dep failure!
  17480.                             return $this->_downloader->_getPackageDownloadUrl(
  17481.                                 array('package' => $pname['package'],
  17482.                                       'channel' => $pname['channel'],
  17483.                                       'version' => $info['version']));
  17484.                         }
  17485.                         $vs = ' within preferred state "' . $this->_config->get('preferred_state') .
  17486.                             '"';
  17487.                     } else {
  17488.                         if (!class_exists('PEAR_Dependency2')) {
  17489.                             require_once 'phar://go-pear.phar/' . 'PEAR/Dependency2.php';
  17490.                         }
  17491.                         if ($optional) {
  17492.                             // don't spit out confusing error message, and don't die on
  17493.                             // optional dep failure!
  17494.                             return $this->_downloader->_getPackageDownloadUrl(
  17495.                                 array('package' => $pname['package'],
  17496.                                       'channel' => $pname['channel'],
  17497.                                       'version' => $info['version']));
  17498.                         }
  17499.                         $vs = PEAR_Dependency2::_getExtraString($pname);
  17500.                     }
  17501.                 } else {
  17502.                     $vs = ' within preferred state "' . $this->_downloader->config->get(
  17503.                         'preferred_state') . '"';
  17504.                 }
  17505.                 $options = $this->_downloader->getOptions();
  17506.                 // this is only set by the "download-all" command
  17507.                 if (isset($options['ignorepreferred_state'])) {
  17508.                     $err = PEAR::raiseError(
  17509.                         'Failed to download ' . $this->_registry->parsedPackageNameToString(
  17510.                             array('channel' => $pname['channel'], 'package' => $pname['package']),
  17511.                                 true)
  17512.                          . $vs .
  17513.                         ', latest release is version ' . $info['version'] .
  17514.                         ', stability "' . $info['info']->getState() . '", use "' .
  17515.                         $this->_registry->parsedPackageNameToString(
  17516.                             array('channel' => $pname['channel'], 'package' => $pname['package'],
  17517.                             'version' => $info['version'])) . '" to install',
  17518.                             PEAR_DOWNLOADER_PACKAGE_STATE);
  17519.                     return $err;
  17520.                 }
  17521.                 $err = PEAR::raiseError(
  17522.                     'Failed to download ' . $this->_registry->parsedPackageNameToString(
  17523.                         array('channel' => $pname['channel'], 'package' => $pname['package']),
  17524.                             true)
  17525.                      . $vs .
  17526.                     ', latest release is version ' . $info['version'] .
  17527.                     ', stability "' . $info['info']->getState() . '", use "' .
  17528.                     $this->_registry->parsedPackageNameToString(
  17529.                         array('channel' => $pname['channel'], 'package' => $pname['package'],
  17530.                         'version' => $info['version'])) . '" to install');
  17531.                 return $err;
  17532.             }
  17533.         }
  17534.         if (isset($info['deprecated']) && $info['deprecated']) {
  17535.             $this->_downloader->log(0,
  17536.                 'WARNING: "' . 
  17537.                     $this->_registry->parsedPackageNameToString(
  17538.                             array('channel' => $info['info']->getChannel(),
  17539.                                   'package' => $info['info']->getPackage()), true) .
  17540.                 '" is deprecated in favor of "' .
  17541.                     $this->_registry->parsedPackageNameToString($info['deprecated'], true) .
  17542.                 '"');
  17543.         }
  17544.         return $info;
  17545.     }
  17546. }
  17547. ?>
  17548. <?php
  17549. /**
  17550.  * Error Stack Implementation
  17551.  * 
  17552.  * This is an incredibly simple implementation of a very complex error handling
  17553.  * facility.  It contains the ability
  17554.  * to track multiple errors from multiple packages simultaneously.  In addition,
  17555.  * it can track errors of many levels, save data along with the error, context
  17556.  * information such as the exact file, line number, class and function that
  17557.  * generated the error, and if necessary, it can raise a traditional PEAR_Error.
  17558.  * It has built-in support for PEAR::Log, to log errors as they occur
  17559.  * 
  17560.  * Since version 0.2alpha, it is also possible to selectively ignore errors,
  17561.  * through the use of an error callback, see {@link pushCallback()}
  17562.  * 
  17563.  * Since version 0.3alpha, it is possible to specify the exception class
  17564.  * returned from {@link push()}
  17565.  *
  17566.  * Since version PEAR1.3.2, ErrorStack no longer instantiates an exception class.  This can
  17567.  * still be done quite handily in an error callback or by manipulating the returned array
  17568.  * @category   Debugging
  17569.  * @package    PEAR_ErrorStack
  17570.  * @author     Greg Beaver <cellog@php.net>
  17571.  * @copyright  2004-2008 Greg Beaver
  17572.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  17573.  * @version    CVS: $Id: ErrorStack.php,v 1.28 2008/01/03 20:26:35 cellog Exp $
  17574.  * @link       http://pear.php.net/package/PEAR_ErrorStack
  17575.  */
  17576.  
  17577. /**
  17578.  * Singleton storage
  17579.  * 
  17580.  * Format:
  17581.  * <pre>
  17582.  * array(
  17583.  *  'package1' => PEAR_ErrorStack object,
  17584.  *  'package2' => PEAR_ErrorStack object,
  17585.  *  ...
  17586.  * )
  17587.  * </pre>
  17588.  * @access private
  17589.  * @global array $GLOBALS['_PEAR_ERRORSTACK_SINGLETON']
  17590.  */
  17591. $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] = array();
  17592.  
  17593. /**
  17594.  * Global error callback (default)
  17595.  * 
  17596.  * This is only used if set to non-false.  * is the default callback for
  17597.  * all packages, whereas specific packages may set a default callback
  17598.  * for all instances, regardless of whether they are a singleton or not.
  17599.  *
  17600.  * To exclude non-singletons, only set the local callback for the singleton
  17601.  * @see PEAR_ErrorStack::setDefaultCallback()
  17602.  * @access private
  17603.  * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK']
  17604.  */
  17605. $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] = array(
  17606.     '*' => false,
  17607. );
  17608.  
  17609. /**
  17610.  * Global Log object (default)
  17611.  * 
  17612.  * This is only used if set to non-false.  Use to set a default log object for
  17613.  * all stacks, regardless of instantiation order or location
  17614.  * @see PEAR_ErrorStack::setDefaultLogger()
  17615.  * @access private
  17616.  * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']
  17617.  */
  17618. $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = false;
  17619.  
  17620. /**
  17621.  * Global Overriding Callback
  17622.  * 
  17623.  * This callback will override any error callbacks that specific loggers have set.
  17624.  * Use with EXTREME caution
  17625.  * @see PEAR_ErrorStack::staticPushCallback()
  17626.  * @access private
  17627.  * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']
  17628.  */
  17629. $GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array();
  17630.  
  17631. /**#@+
  17632.  * One of four possible return values from the error Callback
  17633.  * @see PEAR_ErrorStack::_errorCallback()
  17634.  */
  17635. /**
  17636.  * If this is returned, then the error will be both pushed onto the stack
  17637.  * and logged.
  17638.  */
  17639. define('PEAR_ERRORSTACK_PUSHANDLOG', 1);
  17640. /**
  17641.  * If this is returned, then the error will only be pushed onto the stack,
  17642.  * and not logged.
  17643.  */
  17644. define('PEAR_ERRORSTACK_PUSH', 2);
  17645. /**
  17646.  * If this is returned, then the error will only be logged, but not pushed
  17647.  * onto the error stack.
  17648.  */
  17649. define('PEAR_ERRORSTACK_LOG', 3);
  17650. /**
  17651.  * If this is returned, then the error is completely ignored.
  17652.  */
  17653. define('PEAR_ERRORSTACK_IGNORE', 4);
  17654. /**
  17655.  * If this is returned, then the error is logged and die() is called.
  17656.  */
  17657. define('PEAR_ERRORSTACK_DIE', 5);
  17658. /**#@-*/
  17659.  
  17660. /**
  17661.  * Error code for an attempt to instantiate a non-class as a PEAR_ErrorStack in
  17662.  * the singleton method.
  17663.  */
  17664. define('PEAR_ERRORSTACK_ERR_NONCLASS', 1);
  17665.  
  17666. /**
  17667.  * Error code for an attempt to pass an object into {@link PEAR_ErrorStack::getMessage()}
  17668.  * that has no __toString() method
  17669.  */
  17670. define('PEAR_ERRORSTACK_ERR_OBJTOSTRING', 2);
  17671. /**
  17672.  * Error Stack Implementation
  17673.  *
  17674.  * Usage:
  17675.  * <code>
  17676.  * // global error stack
  17677.  * $global_stack = &PEAR_ErrorStack::singleton('MyPackage');
  17678.  * // local error stack
  17679.  * $local_stack = new PEAR_ErrorStack('MyPackage');
  17680.  * </code>
  17681.  * @author     Greg Beaver <cellog@php.net>
  17682.  * @version    1.7.1
  17683.  * @package    PEAR_ErrorStack
  17684.  * @category   Debugging
  17685.  * @copyright  2004-2008 Greg Beaver
  17686.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  17687.  * @version    CVS: $Id: ErrorStack.php,v 1.28 2008/01/03 20:26:35 cellog Exp $
  17688.  * @link       http://pear.php.net/package/PEAR_ErrorStack
  17689.  */
  17690. class PEAR_ErrorStack {
  17691.     /**
  17692.      * Errors are stored in the order that they are pushed on the stack.
  17693.      * @since 0.4alpha Errors are no longer organized by error level.
  17694.      * This renders pop() nearly unusable, and levels could be more easily
  17695.      * handled in a callback anyway
  17696.      * @var array
  17697.      * @access private
  17698.      */
  17699.     var $_errors = array();
  17700.  
  17701.     /**
  17702.      * Storage of errors by level.
  17703.      *
  17704.      * Allows easy retrieval and deletion of only errors from a particular level
  17705.      * @since PEAR 1.4.0dev
  17706.      * @var array
  17707.      * @access private
  17708.      */
  17709.     var $_errorsByLevel = array();
  17710.  
  17711.     /**
  17712.      * Package name this error stack represents
  17713.      * @var string
  17714.      * @access protected
  17715.      */
  17716.     var $_package;
  17717.     
  17718.     /**
  17719.      * Determines whether a PEAR_Error is thrown upon every error addition
  17720.      * @var boolean
  17721.      * @access private
  17722.      */
  17723.     var $_compat = false;
  17724.     
  17725.     /**
  17726.      * If set to a valid callback, this will be used to generate the error
  17727.      * message from the error code, otherwise the message passed in will be
  17728.      * used
  17729.      * @var false|string|array
  17730.      * @access private
  17731.      */
  17732.     var $_msgCallback = false;
  17733.     
  17734.     /**
  17735.      * If set to a valid callback, this will be used to generate the error
  17736.      * context for an error.  For PHP-related errors, this will be a file
  17737.      * and line number as retrieved from debug_backtrace(), but can be
  17738.      * customized for other purposes.  The error might actually be in a separate
  17739.      * configuration file, or in a database query.
  17740.      * @var false|string|array
  17741.      * @access protected
  17742.      */
  17743.     var $_contextCallback = false;
  17744.     
  17745.     /**
  17746.      * If set to a valid callback, this will be called every time an error
  17747.      * is pushed onto the stack.  The return value will be used to determine
  17748.      * whether to allow an error to be pushed or logged.
  17749.      * 
  17750.      * The return value must be one an PEAR_ERRORSTACK_* constant
  17751.      * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG
  17752.      * @var false|string|array
  17753.      * @access protected
  17754.      */
  17755.     var $_errorCallback = array();
  17756.     
  17757.     /**
  17758.      * PEAR::Log object for logging errors
  17759.      * @var false|Log
  17760.      * @access protected
  17761.      */
  17762.     var $_logger = false;
  17763.     
  17764.     /**
  17765.      * Error messages - designed to be overridden
  17766.      * @var array
  17767.      * @abstract
  17768.      */
  17769.     var $_errorMsgs = array();
  17770.     
  17771.     /**
  17772.      * Set up a new error stack
  17773.      * 
  17774.      * @param string   $package name of the package this error stack represents
  17775.      * @param callback $msgCallback callback used for error message generation
  17776.      * @param callback $contextCallback callback used for context generation,
  17777.      *                 defaults to {@link getFileLine()}
  17778.      * @param boolean  $throwPEAR_Error
  17779.      */
  17780.     function PEAR_ErrorStack($package, $msgCallback = false, $contextCallback = false,
  17781.                          $throwPEAR_Error = false)
  17782.     {
  17783.         $this->_package = $package;
  17784.         $this->setMessageCallback($msgCallback);
  17785.         $this->setContextCallback($contextCallback);
  17786.         $this->_compat = $throwPEAR_Error;
  17787.     }
  17788.     
  17789.     /**
  17790.      * Return a single error stack for this package.
  17791.      * 
  17792.      * Note that all parameters are ignored if the stack for package $package
  17793.      * has already been instantiated
  17794.      * @param string   $package name of the package this error stack represents
  17795.      * @param callback $msgCallback callback used for error message generation
  17796.      * @param callback $contextCallback callback used for context generation,
  17797.      *                 defaults to {@link getFileLine()}
  17798.      * @param boolean  $throwPEAR_Error
  17799.      * @param string   $stackClass class to instantiate
  17800.      * @static
  17801.      * @return PEAR_ErrorStack
  17802.      */
  17803.     function &singleton($package, $msgCallback = false, $contextCallback = false,
  17804.                          $throwPEAR_Error = false, $stackClass = 'PEAR_ErrorStack')
  17805.     {
  17806.         if (isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) {
  17807.             return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package];
  17808.         }
  17809.         if (!class_exists($stackClass)) {
  17810.             if (function_exists('debug_backtrace')) {
  17811.                 $trace = debug_backtrace();
  17812.             }
  17813.             PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_NONCLASS,
  17814.                 'exception', array('stackclass' => $stackClass),
  17815.                 'stack class "%stackclass%" is not a valid class name (should be like PEAR_ErrorStack)',
  17816.                 false, $trace);
  17817.         }
  17818.         $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package] =
  17819.             new $stackClass($package, $msgCallback, $contextCallback, $throwPEAR_Error);
  17820.  
  17821.         return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package];
  17822.     }
  17823.  
  17824.     /**
  17825.      * Internal error handler for PEAR_ErrorStack class
  17826.      * 
  17827.      * Dies if the error is an exception (and would have died anyway)
  17828.      * @access private
  17829.      */
  17830.     function _handleError($err)
  17831.     {
  17832.         if ($err['level'] == 'exception') {
  17833.             $message = $err['message'];
  17834.             if (isset($_SERVER['REQUEST_URI'])) {
  17835.                 echo '<br />';
  17836.             } else {
  17837.                 echo "\n";
  17838.             }
  17839.             var_dump($err['context']);
  17840.             die($message);
  17841.         }
  17842.     }
  17843.     
  17844.     /**
  17845.      * Set up a PEAR::Log object for all error stacks that don't have one
  17846.      * @param Log $log 
  17847.      * @static
  17848.      */
  17849.     function setDefaultLogger(&$log)
  17850.     {
  17851.         if (is_object($log) && method_exists($log, 'log') ) {
  17852.             $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log;
  17853.         } elseif (is_callable($log)) {
  17854.             $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log;
  17855.     }
  17856.     }
  17857.     
  17858.     /**
  17859.      * Set up a PEAR::Log object for this error stack
  17860.      * @param Log $log 
  17861.      */
  17862.     function setLogger(&$log)
  17863.     {
  17864.         if (is_object($log) && method_exists($log, 'log') ) {
  17865.             $this->_logger = &$log;
  17866.         } elseif (is_callable($log)) {
  17867.             $this->_logger = &$log;
  17868.         }
  17869.     }
  17870.     
  17871.     /**
  17872.      * Set an error code => error message mapping callback
  17873.      * 
  17874.      * This method sets the callback that can be used to generate error
  17875.      * messages for any instance
  17876.      * @param array|string Callback function/method
  17877.      */
  17878.     function setMessageCallback($msgCallback)
  17879.     {
  17880.         if (!$msgCallback) {
  17881.             $this->_msgCallback = array(&$this, 'getErrorMessage');
  17882.         } else {
  17883.             if (is_callable($msgCallback)) {
  17884.                 $this->_msgCallback = $msgCallback;
  17885.             }
  17886.         }
  17887.     }
  17888.     
  17889.     /**
  17890.      * Get an error code => error message mapping callback
  17891.      * 
  17892.      * This method returns the current callback that can be used to generate error
  17893.      * messages
  17894.      * @return array|string|false Callback function/method or false if none
  17895.      */
  17896.     function getMessageCallback()
  17897.     {
  17898.         return $this->_msgCallback;
  17899.     }
  17900.     
  17901.     /**
  17902.      * Sets a default callback to be used by all error stacks
  17903.      * 
  17904.      * This method sets the callback that can be used to generate error
  17905.      * messages for a singleton
  17906.      * @param array|string Callback function/method
  17907.      * @param string Package name, or false for all packages
  17908.      * @static
  17909.      */
  17910.     function setDefaultCallback($callback = false, $package = false)
  17911.     {
  17912.         if (!is_callable($callback)) {
  17913.             $callback = false;
  17914.         }
  17915.         $package = $package ? $package : '*';
  17916.         $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$package] = $callback;
  17917.     }
  17918.     
  17919.     /**
  17920.      * Set a callback that generates context information (location of error) for an error stack
  17921.      * 
  17922.      * This method sets the callback that can be used to generate context
  17923.      * information for an error.  Passing in NULL will disable context generation
  17924.      * and remove the expensive call to debug_backtrace()
  17925.      * @param array|string|null Callback function/method
  17926.      */
  17927.     function setContextCallback($contextCallback)
  17928.     {
  17929.         if ($contextCallback === null) {
  17930.             return $this->_contextCallback = false;
  17931.         }
  17932.         if (!$contextCallback) {
  17933.             $this->_contextCallback = array(&$this, 'getFileLine');
  17934.         } else {
  17935.             if (is_callable($contextCallback)) {
  17936.                 $this->_contextCallback = $contextCallback;
  17937.             }
  17938.         }
  17939.     }
  17940.     
  17941.     /**
  17942.      * Set an error Callback
  17943.      * If set to a valid callback, this will be called every time an error
  17944.      * is pushed onto the stack.  The return value will be used to determine
  17945.      * whether to allow an error to be pushed or logged.
  17946.      * 
  17947.      * The return value must be one of the ERRORSTACK_* constants.
  17948.      * 
  17949.      * This functionality can be used to emulate PEAR's pushErrorHandling, and
  17950.      * the PEAR_ERROR_CALLBACK mode, without affecting the integrity of
  17951.      * the error stack or logging
  17952.      * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG
  17953.      * @see popCallback()
  17954.      * @param string|array $cb
  17955.      */
  17956.     function pushCallback($cb)
  17957.     {
  17958.         array_push($this->_errorCallback, $cb);
  17959.     }
  17960.     
  17961.     /**
  17962.      * Remove a callback from the error callback stack
  17963.      * @see pushCallback()
  17964.      * @return array|string|false
  17965.      */
  17966.     function popCallback()
  17967.     {
  17968.         if (!count($this->_errorCallback)) {
  17969.             return false;
  17970.         }
  17971.         return array_pop($this->_errorCallback);
  17972.     }
  17973.     
  17974.     /**
  17975.      * Set a temporary overriding error callback for every package error stack
  17976.      *
  17977.      * Use this to temporarily disable all existing callbacks (can be used
  17978.      * to emulate the @ operator, for instance)
  17979.      * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG
  17980.      * @see staticPopCallback(), pushCallback()
  17981.      * @param string|array $cb
  17982.      * @static
  17983.      */
  17984.     function staticPushCallback($cb)
  17985.     {
  17986.         array_push($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'], $cb);
  17987.     }
  17988.     
  17989.     /**
  17990.      * Remove a temporary overriding error callback
  17991.      * @see staticPushCallback()
  17992.      * @return array|string|false
  17993.      * @static
  17994.      */
  17995.     function staticPopCallback()
  17996.     {
  17997.         $ret = array_pop($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK']);
  17998.         if (!is_array($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'])) {
  17999.             $GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array();
  18000.         }
  18001.         return $ret;
  18002.     }
  18003.     
  18004.     /**
  18005.      * Add an error to the stack
  18006.      * 
  18007.      * If the message generator exists, it is called with 2 parameters.
  18008.      *  - the current Error Stack object
  18009.      *  - an array that is in the same format as an error.  Available indices
  18010.      *    are 'code', 'package', 'time', 'params', 'level', and 'context'
  18011.      * 
  18012.      * Next, if the error should contain context information, this is
  18013.      * handled by the context grabbing method.
  18014.      * Finally, the error is pushed onto the proper error stack
  18015.      * @param int    $code      Package-specific error code
  18016.      * @param string $level     Error level.  This is NOT spell-checked
  18017.      * @param array  $params    associative array of error parameters
  18018.      * @param string $msg       Error message, or a portion of it if the message
  18019.      *                          is to be generated
  18020.      * @param array  $repackage If this error re-packages an error pushed by
  18021.      *                          another package, place the array returned from
  18022.      *                          {@link pop()} in this parameter
  18023.      * @param array  $backtrace Protected parameter: use this to pass in the
  18024.      *                          {@link debug_backtrace()} that should be used
  18025.      *                          to find error context
  18026.      * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also
  18027.      * thrown.  If a PEAR_Error is returned, the userinfo
  18028.      * property is set to the following array:
  18029.      * 
  18030.      * <code>
  18031.      * array(
  18032.      *    'code' => $code,
  18033.      *    'params' => $params,
  18034.      *    'package' => $this->_package,
  18035.      *    'level' => $level,
  18036.      *    'time' => time(),
  18037.      *    'context' => $context,
  18038.      *    'message' => $msg,
  18039.      * //['repackage' => $err] repackaged error array/Exception class
  18040.      * );
  18041.      * </code>
  18042.      * 
  18043.      * Normally, the previous array is returned.
  18044.      */
  18045.     function push($code, $level = 'error', $params = array(), $msg = false,
  18046.                   $repackage = false, $backtrace = false)
  18047.     {
  18048.         $context = false;
  18049.         // grab error context
  18050.         if ($this->_contextCallback) {
  18051.             if (!$backtrace) {
  18052.                 $backtrace = debug_backtrace();
  18053.             }
  18054.             $context = call_user_func($this->_contextCallback, $code, $params, $backtrace);
  18055.         }
  18056.         
  18057.         // save error
  18058.         $time = explode(' ', microtime());
  18059.         $time = $time[1] + $time[0];
  18060.         $err = array(
  18061.                 'code' => $code,
  18062.                 'params' => $params,
  18063.                 'package' => $this->_package,
  18064.                 'level' => $level,
  18065.                 'time' => $time,
  18066.                 'context' => $context,
  18067.                 'message' => $msg,
  18068.                );
  18069.  
  18070.         if ($repackage) {
  18071.             $err['repackage'] = $repackage;
  18072.         }
  18073.  
  18074.         // set up the error message, if necessary
  18075.         if ($this->_msgCallback) {
  18076.             $msg = call_user_func_array($this->_msgCallback,
  18077.                                         array(&$this, $err));
  18078.             $err['message'] = $msg;
  18079.         }        
  18080.         $push = $log = true;
  18081.         $die = false;
  18082.         // try the overriding callback first
  18083.         $callback = $this->staticPopCallback();
  18084.         if ($callback) {
  18085.             $this->staticPushCallback($callback);
  18086.         }
  18087.         if (!is_callable($callback)) {
  18088.             // try the local callback next
  18089.             $callback = $this->popCallback();
  18090.             if (is_callable($callback)) {
  18091.                 $this->pushCallback($callback);
  18092.             } else {
  18093.                 // try the default callback
  18094.                 $callback = isset($GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package]) ?
  18095.                     $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package] :
  18096.                     $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK']['*'];
  18097.             }
  18098.         }
  18099.         if (is_callable($callback)) {
  18100.             switch(call_user_func($callback, $err)){
  18101.                 case PEAR_ERRORSTACK_IGNORE: 
  18102.                     return $err;
  18103.                 break;
  18104.                 case PEAR_ERRORSTACK_PUSH: 
  18105.                     $log = false;
  18106.                 break;
  18107.                 case PEAR_ERRORSTACK_LOG: 
  18108.                     $push = false;
  18109.                 break;
  18110.                 case PEAR_ERRORSTACK_DIE: 
  18111.                     $die = true;
  18112.                 break;
  18113.                 // anything else returned has the same effect as pushandlog
  18114.             }
  18115.         }
  18116.         if ($push) {
  18117.             array_unshift($this->_errors, $err);
  18118.             if (!isset($this->_errorsByLevel[$err['level']])) {
  18119.                 $this->_errorsByLevel[$err['level']] = array();
  18120.             }
  18121.             $this->_errorsByLevel[$err['level']][] = &$this->_errors[0];
  18122.         }
  18123.         if ($log) {
  18124.             if ($this->_logger || $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']) {
  18125.                 $this->_log($err);
  18126.             }
  18127.         }
  18128.         if ($die) {
  18129.             die();
  18130.         }
  18131.         if ($this->_compat && $push) {
  18132.             return $this->raiseError($msg, $code, null, null, $err);
  18133.         }
  18134.         return $err;
  18135.     }
  18136.     
  18137.     /**
  18138.      * Static version of {@link push()}
  18139.      * 
  18140.      * @param string $package   Package name this error belongs to
  18141.      * @param int    $code      Package-specific error code
  18142.      * @param string $level     Error level.  This is NOT spell-checked
  18143.      * @param array  $params    associative array of error parameters
  18144.      * @param string $msg       Error message, or a portion of it if the message
  18145.      *                          is to be generated
  18146.      * @param array  $repackage If this error re-packages an error pushed by
  18147.      *                          another package, place the array returned from
  18148.      *                          {@link pop()} in this parameter
  18149.      * @param array  $backtrace Protected parameter: use this to pass in the
  18150.      *                          {@link debug_backtrace()} that should be used
  18151.      *                          to find error context
  18152.      * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also
  18153.      *                          thrown.  see docs for {@link push()}
  18154.      * @static
  18155.      */
  18156.     function staticPush($package, $code, $level = 'error', $params = array(),
  18157.                         $msg = false, $repackage = false, $backtrace = false)
  18158.     {
  18159.         $s = &PEAR_ErrorStack::singleton($package);
  18160.         if ($s->_contextCallback) {
  18161.             if (!$backtrace) {
  18162.                 if (function_exists('debug_backtrace')) {
  18163.                     $backtrace = debug_backtrace();
  18164.                 }
  18165.             }
  18166.         }
  18167.         return $s->push($code, $level, $params, $msg, $repackage, $backtrace);
  18168.     }
  18169.     
  18170.     /**
  18171.      * Log an error using PEAR::Log
  18172.      * @param array $err Error array
  18173.      * @param array $levels Error level => Log constant map
  18174.      * @access protected
  18175.      */
  18176.     function _log($err)
  18177.     {
  18178.         if ($this->_logger) {
  18179.             $logger = &$this->_logger;
  18180.         } else {
  18181.             $logger = &$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'];
  18182.         }
  18183.         if (is_a($logger, 'Log')) {
  18184.             $levels = array(
  18185.                 'exception' => PEAR_LOG_CRIT,
  18186.                 'alert' => PEAR_LOG_ALERT,
  18187.                 'critical' => PEAR_LOG_CRIT,
  18188.                 'error' => PEAR_LOG_ERR,
  18189.                 'warning' => PEAR_LOG_WARNING,
  18190.                 'notice' => PEAR_LOG_NOTICE,
  18191.                 'info' => PEAR_LOG_INFO,
  18192.                 'debug' => PEAR_LOG_DEBUG);
  18193.             if (isset($levels[$err['level']])) {
  18194.                 $level = $levels[$err['level']];
  18195.             } else {
  18196.                 $level = PEAR_LOG_INFO;
  18197.             }
  18198.             $logger->log($err['message'], $level, $err);
  18199.         } else { // support non-standard logs
  18200.             call_user_func($logger, $err);
  18201.         }
  18202.     }
  18203.  
  18204.     
  18205.     /**
  18206.      * Pop an error off of the error stack
  18207.      * 
  18208.      * @return false|array
  18209.      * @since 0.4alpha it is no longer possible to specify a specific error
  18210.      * level to return - the last error pushed will be returned, instead
  18211.      */
  18212.     function pop()
  18213.     {
  18214.         $err = @array_shift($this->_errors);
  18215.         if (!is_null($err)) {
  18216.             @array_pop($this->_errorsByLevel[$err['level']]);
  18217.             if (!count($this->_errorsByLevel[$err['level']])) {
  18218.                 unset($this->_errorsByLevel[$err['level']]);
  18219.             }
  18220.         }
  18221.         return $err;
  18222.     }
  18223.  
  18224.     /**
  18225.      * Pop an error off of the error stack, static method
  18226.      *
  18227.      * @param string package name
  18228.      * @return boolean
  18229.      * @since PEAR1.5.0a1
  18230.      */
  18231.     function staticPop($package)
  18232.     {
  18233.         if ($package) {
  18234.             if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) {
  18235.                 return false;
  18236.             }
  18237.             return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->pop();
  18238.         }
  18239.     }
  18240.  
  18241.     /**
  18242.      * Determine whether there are any errors on the stack
  18243.      * @param string|array Level name.  Use to determine if any errors
  18244.      * of level (string), or levels (array) have been pushed
  18245.      * @return boolean
  18246.      */
  18247.     function hasErrors($level = false)
  18248.     {
  18249.         if ($level) {
  18250.             return isset($this->_errorsByLevel[$level]);
  18251.         }
  18252.         return count($this->_errors);
  18253.     }
  18254.     
  18255.     /**
  18256.      * Retrieve all errors since last purge
  18257.      * 
  18258.      * @param boolean set in order to empty the error stack
  18259.      * @param string level name, to return only errors of a particular severity
  18260.      * @return array
  18261.      */
  18262.     function getErrors($purge = false, $level = false)
  18263.     {
  18264.         if (!$purge) {
  18265.             if ($level) {
  18266.                 if (!isset($this->_errorsByLevel[$level])) {
  18267.                     return array();
  18268.                 } else {
  18269.                     return $this->_errorsByLevel[$level];
  18270.                 }
  18271.             } else {
  18272.                 return $this->_errors;
  18273.             }
  18274.         }
  18275.         if ($level) {
  18276.             $ret = $this->_errorsByLevel[$level];
  18277.             foreach ($this->_errorsByLevel[$level] as $i => $unused) {
  18278.                 // entries are references to the $_errors array
  18279.                 $this->_errorsByLevel[$level][$i] = false;
  18280.             }
  18281.             // array_filter removes all entries === false
  18282.             $this->_errors = array_filter($this->_errors);
  18283.             unset($this->_errorsByLevel[$level]);
  18284.             return $ret;
  18285.         }
  18286.         $ret = $this->_errors;
  18287.         $this->_errors = array();
  18288.         $this->_errorsByLevel = array();
  18289.         return $ret;
  18290.     }
  18291.     
  18292.     /**
  18293.      * Determine whether there are any errors on a single error stack, or on any error stack
  18294.      *
  18295.      * The optional parameter can be used to test the existence of any errors without the need of
  18296.      * singleton instantiation
  18297.      * @param string|false Package name to check for errors
  18298.      * @param string Level name to check for a particular severity
  18299.      * @return boolean
  18300.      * @static
  18301.      */
  18302.     function staticHasErrors($package = false, $level = false)
  18303.     {
  18304.         if ($package) {
  18305.             if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) {
  18306.                 return false;
  18307.             }
  18308.             return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->hasErrors($level);
  18309.         }
  18310.         foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) {
  18311.             if ($obj->hasErrors($level)) {
  18312.                 return true;
  18313.             }
  18314.         }
  18315.         return false;
  18316.     }
  18317.     
  18318.     /**
  18319.      * Get a list of all errors since last purge, organized by package
  18320.      * @since PEAR 1.4.0dev BC break! $level is now in the place $merge used to be
  18321.      * @param boolean $purge Set to purge the error stack of existing errors
  18322.      * @param string  $level Set to a level name in order to retrieve only errors of a particular level
  18323.      * @param boolean $merge Set to return a flat array, not organized by package
  18324.      * @param array   $sortfunc Function used to sort a merged array - default
  18325.      *        sorts by time, and should be good for most cases
  18326.      * @static
  18327.      * @return array 
  18328.      */
  18329.     function staticGetErrors($purge = false, $level = false, $merge = false,
  18330.                              $sortfunc = array('PEAR_ErrorStack', '_sortErrors'))
  18331.     {
  18332.         $ret = array();
  18333.         if (!is_callable($sortfunc)) {
  18334.             $sortfunc = array('PEAR_ErrorStack', '_sortErrors');
  18335.         }
  18336.         foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) {
  18337.             $test = $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->getErrors($purge, $level);
  18338.             if ($test) {
  18339.                 if ($merge) {
  18340.                     $ret = array_merge($ret, $test);
  18341.                 } else {
  18342.                     $ret[$package] = $test;
  18343.                 }
  18344.             }
  18345.         }
  18346.         if ($merge) {
  18347.             usort($ret, $sortfunc);
  18348.         }
  18349.         return $ret;
  18350.     }
  18351.     
  18352.     /**
  18353.      * Error sorting function, sorts by time
  18354.      * @access private
  18355.      */
  18356.     function _sortErrors($a, $b)
  18357.     {
  18358.         if ($a['time'] == $b['time']) {
  18359.             return 0;
  18360.         }
  18361.         if ($a['time'] < $b['time']) {
  18362.             return 1;
  18363.         }
  18364.         return -1;
  18365.     }
  18366.  
  18367.     /**
  18368.      * Standard file/line number/function/class context callback
  18369.      *
  18370.      * This function uses a backtrace generated from {@link debug_backtrace()}
  18371.      * and so will not work at all in PHP < 4.3.0.  The frame should
  18372.      * reference the frame that contains the source of the error.
  18373.      * @return array|false either array('file' => file, 'line' => line,
  18374.      *         'function' => function name, 'class' => class name) or
  18375.      *         if this doesn't work, then false
  18376.      * @param unused
  18377.      * @param integer backtrace frame.
  18378.      * @param array Results of debug_backtrace()
  18379.      * @static
  18380.      */
  18381.     function getFileLine($code, $params, $backtrace = null)
  18382.     {
  18383.         if ($backtrace === null) {
  18384.             return false;
  18385.         }
  18386.         $frame = 0;
  18387.         $functionframe = 1;
  18388.         if (!isset($backtrace[1])) {
  18389.             $functionframe = 0;
  18390.         } else {
  18391.             while (isset($backtrace[$functionframe]['function']) &&
  18392.                   $backtrace[$functionframe]['function'] == 'eval' &&
  18393.                   isset($backtrace[$functionframe + 1])) {
  18394.                 $functionframe++;
  18395.             }
  18396.         }
  18397.         if (isset($backtrace[$frame])) {
  18398.             if (!isset($backtrace[$frame]['file'])) {
  18399.                 $frame++;
  18400.             }
  18401.             $funcbacktrace = $backtrace[$functionframe];
  18402.             $filebacktrace = $backtrace[$frame];
  18403.             $ret = array('file' => $filebacktrace['file'],
  18404.                          'line' => $filebacktrace['line']);
  18405.             // rearrange for eval'd code or create function errors
  18406.             if (strpos($filebacktrace['file'], '(') && 
  18407.                   preg_match(';^(.*?)\((\d+)\) : (.*?)\\z;', $filebacktrace['file'],
  18408.                   $matches)) {
  18409.                 $ret['file'] = $matches[1];
  18410.                 $ret['line'] = $matches[2] + 0;
  18411.             }
  18412.             if (isset($funcbacktrace['function']) && isset($backtrace[1])) {
  18413.                 if ($funcbacktrace['function'] != 'eval') {
  18414.                     if ($funcbacktrace['function'] == '__lambda_func') {
  18415.                         $ret['function'] = 'create_function() code';
  18416.                     } else {
  18417.                         $ret['function'] = $funcbacktrace['function'];
  18418.                     }
  18419.                 }
  18420.             }
  18421.             if (isset($funcbacktrace['class']) && isset($backtrace[1])) {
  18422.                 $ret['class'] = $funcbacktrace['class'];
  18423.             }
  18424.             return $ret;
  18425.         }
  18426.         return false;
  18427.     }
  18428.     
  18429.     /**
  18430.      * Standard error message generation callback
  18431.      * 
  18432.      * This method may also be called by a custom error message generator
  18433.      * to fill in template values from the params array, simply
  18434.      * set the third parameter to the error message template string to use
  18435.      * 
  18436.      * The special variable %__msg% is reserved: use it only to specify
  18437.      * where a message passed in by the user should be placed in the template,
  18438.      * like so:
  18439.      * 
  18440.      * Error message: %msg% - internal error
  18441.      * 
  18442.      * If the message passed like so:
  18443.      * 
  18444.      * <code>
  18445.      * $stack->push(ERROR_CODE, 'error', array(), 'server error 500');
  18446.      * </code>
  18447.      * 
  18448.      * The returned error message will be "Error message: server error 500 -
  18449.      * internal error"
  18450.      * @param PEAR_ErrorStack
  18451.      * @param array
  18452.      * @param string|false Pre-generated error message template
  18453.      * @static
  18454.      * @return string
  18455.      */
  18456.     function getErrorMessage(&$stack, $err, $template = false)
  18457.     {
  18458.         if ($template) {
  18459.             $mainmsg = $template;
  18460.         } else {
  18461.             $mainmsg = $stack->getErrorMessageTemplate($err['code']);
  18462.         }
  18463.         $mainmsg = str_replace('%__msg%', $err['message'], $mainmsg);
  18464.         if (is_array($err['params']) && count($err['params'])) {
  18465.             foreach ($err['params'] as $name => $val) {
  18466.                 if (is_array($val)) {
  18467.                     // @ is needed in case $val is a multi-dimensional array
  18468.                     $val = @implode(', ', $val);
  18469.                 }
  18470.                 if (is_object($val)) {
  18471.                     if (method_exists($val, '__toString')) {
  18472.                         $val = $val->__toString();
  18473.                     } else {
  18474.                         PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_OBJTOSTRING,
  18475.                             'warning', array('obj' => get_class($val)),
  18476.                             'object %obj% passed into getErrorMessage, but has no __toString() method');
  18477.                         $val = 'Object';
  18478.                     }
  18479.                 }
  18480.                 $mainmsg = str_replace('%' . $name . '%', $val, $mainmsg);
  18481.             }
  18482.         }
  18483.         return $mainmsg;
  18484.     }
  18485.     
  18486.     /**
  18487.      * Standard Error Message Template generator from code
  18488.      * @return string
  18489.      */
  18490.     function getErrorMessageTemplate($code)
  18491.     {
  18492.         if (!isset($this->_errorMsgs[$code])) {
  18493.             return '%__msg%';
  18494.         }
  18495.         return $this->_errorMsgs[$code];
  18496.     }
  18497.     
  18498.     /**
  18499.      * Set the Error Message Template array
  18500.      * 
  18501.      * The array format must be:
  18502.      * <pre>
  18503.      * array(error code => 'message template',...)
  18504.      * </pre>
  18505.      * 
  18506.      * Error message parameters passed into {@link push()} will be used as input
  18507.      * for the error message.  If the template is 'message %foo% was %bar%', and the
  18508.      * parameters are array('foo' => 'one', 'bar' => 'six'), the error message returned will
  18509.      * be 'message one was six'
  18510.      * @return string
  18511.      */
  18512.     function setErrorMessageTemplate($template)
  18513.     {
  18514.         $this->_errorMsgs = $template;
  18515.     }
  18516.     
  18517.     
  18518.     /**
  18519.      * emulate PEAR::raiseError()
  18520.      * 
  18521.      * @return PEAR_Error
  18522.      */
  18523.     function raiseError()
  18524.     {
  18525.         require_once 'phar://go-pear.phar/' . 'PEAR.php';
  18526.         $args = func_get_args();
  18527.         return call_user_func_array(array('PEAR', 'raiseError'), $args);
  18528.     }
  18529. }
  18530. $stack = &PEAR_ErrorStack::singleton('PEAR_ErrorStack');
  18531. $stack->pushCallback(array('PEAR_ErrorStack', '_handleError'));
  18532. ?>
  18533. <?php
  18534. /**
  18535.  * PEAR_Frontend, the singleton-based frontend for user input/output
  18536.  *
  18537.  * PHP versions 4 and 5
  18538.  *
  18539.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  18540.  * that is available through the world-wide-web at the following URI:
  18541.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  18542.  * the PHP License and are unable to obtain it through the web, please
  18543.  * send a note to license@php.net so we can mail you a copy immediately.
  18544.  *
  18545.  * @category   pear
  18546.  * @package    PEAR
  18547.  * @author     Greg Beaver <cellog@php.net>
  18548.  * @copyright  1997-2008 The PHP Group
  18549.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  18550.  * @version    CVS: $Id: Frontend.php,v 1.13 2008/01/03 20:26:35 cellog Exp $
  18551.  * @link       http://pear.php.net/package/PEAR
  18552.  * @since      File available since Release 1.4.0a1
  18553.  */
  18554.  
  18555. /**
  18556.  * Which user interface class is being used.
  18557.  * @var string class name
  18558.  */
  18559. $GLOBALS['_PEAR_FRONTEND_CLASS'] = 'PEAR_Frontend_CLI';
  18560.  
  18561. /**
  18562.  * Instance of $_PEAR_Command_uiclass.
  18563.  * @var object
  18564.  */
  18565. $GLOBALS['_PEAR_FRONTEND_SINGLETON'] = null;
  18566.  
  18567. /**
  18568.  * Singleton-based frontend for PEAR user input/output
  18569.  *
  18570.  * @category   pear
  18571.  * @package    PEAR
  18572.  * @author     Greg Beaver <cellog@php.net>
  18573.  * @copyright  1997-2008 The PHP Group
  18574.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  18575.  * @version    Release: 1.7.1
  18576.  * @link       http://pear.php.net/package/PEAR
  18577.  * @since      Class available since Release 1.4.0a1
  18578.  */
  18579. class PEAR_Frontend extends PEAR
  18580. {
  18581.     /**
  18582.      * Retrieve the frontend object
  18583.      * @return PEAR_Frontend_CLI|PEAR_Frontend_Web|PEAR_Frontend_Gtk
  18584.      * @static
  18585.      */
  18586.     function &singleton($type = null)
  18587.     {
  18588.         if ($type === null) {
  18589.             if (!isset($GLOBALS['_PEAR_FRONTEND_SINGLETON'])) {
  18590.                 $a = false;
  18591.                 return $a;
  18592.             }
  18593.             return $GLOBALS['_PEAR_FRONTEND_SINGLETON'];
  18594.         } else {
  18595.             $a = PEAR_Frontend::setFrontendClass($type);
  18596.             return $a;
  18597.         }
  18598.     }
  18599.  
  18600.     /**
  18601.      * Set the frontend class that will be used by calls to {@link singleton()}
  18602.      *
  18603.      * Frontends are expected to conform to the PEAR naming standard of
  18604.      * _ => DIRECTORY_SEPARATOR (PEAR_Frontend_CLI is in PEAR/Frontend/CLI.php)
  18605.      * @param string $uiclass full class name
  18606.      * @return PEAR_Frontend
  18607.      * @static
  18608.      */
  18609.     function &setFrontendClass($uiclass)
  18610.     {
  18611.         if (is_object($GLOBALS['_PEAR_FRONTEND_SINGLETON']) &&
  18612.               is_a($GLOBALS['_PEAR_FRONTEND_SINGLETON'], $uiclass)) {
  18613.             return $GLOBALS['_PEAR_FRONTEND_SINGLETON'];
  18614.         }
  18615.         if (!class_exists($uiclass)) {
  18616.             $file = 'phar://go-pear.phar/' . str_replace('_', '/', $uiclass) . '.php';
  18617.             if (PEAR_Frontend::isIncludeable($file)) {
  18618.                 include_once $file;
  18619.             }
  18620.         }
  18621.         if (class_exists($uiclass)) {
  18622.             $obj = &new $uiclass;
  18623.             // quick test to see if this class implements a few of the most
  18624.             // important frontend methods
  18625.             if (is_a($obj, 'PEAR_Frontend')) {
  18626.                 $GLOBALS['_PEAR_FRONTEND_SINGLETON'] = &$obj;
  18627.                 $GLOBALS['_PEAR_FRONTEND_CLASS'] = $uiclass;
  18628.                 return $obj;
  18629.             } else {
  18630.                 $err = PEAR::raiseError("not a frontend class: $uiclass");
  18631.                 return $err;
  18632.             }
  18633.         }
  18634.         $err = PEAR::raiseError("no such class: $uiclass");
  18635.         return $err;
  18636.     }
  18637.  
  18638.     /**
  18639.      * Set the frontend class that will be used by calls to {@link singleton()}
  18640.      *
  18641.      * Frontends are expected to be a descendant of PEAR_Frontend
  18642.      * @param PEAR_Frontend
  18643.      * @return PEAR_Frontend
  18644.      * @static
  18645.      */
  18646.     function &setFrontendObject($uiobject)
  18647.     {
  18648.         if (is_object($GLOBALS['_PEAR_FRONTEND_SINGLETON']) &&
  18649.               is_a($GLOBALS['_PEAR_FRONTEND_SINGLETON'], get_class($uiobject))) {
  18650.             return $GLOBALS['_PEAR_FRONTEND_SINGLETON'];
  18651.         }
  18652.         if (!is_a($uiobject, 'PEAR_Frontend')) {
  18653.             $err = PEAR::raiseError('not a valid frontend class: (' .
  18654.                 get_class($uiobject) . ')');
  18655.             return $err;
  18656.         }
  18657.         $GLOBALS['_PEAR_FRONTEND_SINGLETON'] = &$uiobject;
  18658.         $GLOBALS['_PEAR_FRONTEND_CLASS'] = get_class($uiobject);
  18659.         return $uiobject;
  18660.     }
  18661.  
  18662.     /**
  18663.      * @param string $path relative or absolute include path
  18664.      * @return boolean
  18665.      * @static
  18666.      */
  18667.     function isIncludeable($path)
  18668.     {
  18669.         if (file_exists($path) && is_readable($path)) {
  18670.             return true;
  18671.         }
  18672.         $fp = @fopen($path, 'r', true);
  18673.         if ($fp) {
  18674.             fclose($fp);
  18675.             return true;
  18676.         }
  18677.         return false;
  18678.     }
  18679.  
  18680.     /**
  18681.      * @param PEAR_Config
  18682.      */
  18683.     function setConfig(&$config)
  18684.     {
  18685.     }
  18686.  
  18687.     /**
  18688.      * This can be overridden to allow session-based temporary file management
  18689.      *
  18690.      * By default, all files are deleted at the end of a session.  The web installer
  18691.      * needs to be able to sustain a list over many sessions in order to support
  18692.      * user interaction with install scripts
  18693.      */
  18694.     function addTempFile($file)
  18695.     {
  18696.         $GLOBALS['_PEAR_Common_tempfiles'][] = $file;
  18697.     }
  18698.  
  18699.     /**
  18700.      * Log an action
  18701.      *
  18702.      * @param string $msg the message to log
  18703.      * @param boolean $append_crlf
  18704.      * @return boolean true
  18705.      * @abstract
  18706.      */
  18707.     function log($msg, $append_crlf = true)
  18708.     {
  18709.     }
  18710.  
  18711.     /**
  18712.      * Run a post-installation script
  18713.      *
  18714.      * @param array $scripts array of post-install scripts
  18715.      * @abstract
  18716.      */
  18717.     function runPostinstallScripts(&$scripts)
  18718.     {
  18719.     }
  18720.  
  18721.     /**
  18722.      * Display human-friendly output formatted depending on the
  18723.      * $command parameter.
  18724.      *
  18725.      * This should be able to handle basic output data with no command
  18726.      * @param mixed  $data    data structure containing the information to display
  18727.      * @param string $command command from which this method was called
  18728.      * @abstract
  18729.      */
  18730.     function outputData($data, $command = '_default')
  18731.     {
  18732.     }
  18733.  
  18734.     /**
  18735.      * Display a modal form dialog and return the given input
  18736.      *
  18737.      * A frontend that requires multiple requests to retrieve and process
  18738.      * data must take these needs into account, and implement the request
  18739.      * handling code.
  18740.      * @param string $command  command from which this method was called
  18741.      * @param array  $prompts  associative array. keys are the input field names
  18742.      *                         and values are the description
  18743.      * @param array  $types    array of input field types (text, password,
  18744.      *                         etc.) keys have to be the same like in $prompts
  18745.      * @param array  $defaults array of default values. again keys have
  18746.      *                         to be the same like in $prompts.  Do not depend
  18747.      *                         on a default value being set.
  18748.      * @return array input sent by the user
  18749.      * @abstract
  18750.      */
  18751.     function userDialog($command, $prompts, $types = array(), $defaults = array())
  18752.     {
  18753.     }
  18754. }
  18755. ?><?php
  18756. /**
  18757.  * PEAR_Frontend_CLI
  18758.  *
  18759.  * PHP versions 4 and 5
  18760.  *
  18761.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  18762.  * that is available through the world-wide-web at the following URI:
  18763.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  18764.  * the PHP License and are unable to obtain it through the web, please
  18765.  * send a note to license@php.net so we can mail you a copy immediately.
  18766.  *
  18767.  * @category   pear
  18768.  * @package    PEAR
  18769.  * @author     Stig Bakken <ssb@php.net>
  18770.  * @author     Greg Beaver <cellog@php.net>
  18771.  * @copyright  1997-2008 The PHP Group
  18772.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  18773.  * @version    CVS: $Id: CLI.php,v 1.68 2008/01/03 20:26:36 cellog Exp $
  18774.  * @link       http://pear.php.net/package/PEAR
  18775.  * @since      File available since Release 0.1
  18776.  */
  18777. /**
  18778.  * base class
  18779.  */
  18780. require_once 'phar://go-pear.phar/' . 'PEAR/Frontend.php';
  18781.  
  18782. /**
  18783.  * Command-line Frontend for the PEAR Installer
  18784.  * @category   pear
  18785.  * @package    PEAR
  18786.  * @author     Stig Bakken <ssb@php.net>
  18787.  * @author     Greg Beaver <cellog@php.net>
  18788.  * @copyright  1997-2008 The PHP Group
  18789.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  18790.  * @version    Release: 1.7.1
  18791.  * @link       http://pear.php.net/package/PEAR
  18792.  * @since      Class available since Release 0.1
  18793.  */
  18794. class PEAR_Frontend_CLI extends PEAR_Frontend
  18795. {
  18796.     // {{{ properties
  18797.  
  18798.     /**
  18799.      * What type of user interface this frontend is for.
  18800.      * @var string
  18801.      * @access public
  18802.      */
  18803.     var $type = 'CLI';
  18804.     var $lp = ''; // line prefix
  18805.  
  18806.     var $params = array();
  18807.     var $term = array(
  18808.         'bold' => '',
  18809.         'normal' => '',
  18810.         );
  18811.  
  18812.     // }}}
  18813.  
  18814.     // {{{ constructor
  18815.  
  18816.     function PEAR_Frontend_CLI()
  18817.     {
  18818.         parent::PEAR();
  18819.         $term = getenv('TERM'); //(cox) $_ENV is empty for me in 4.1.1
  18820.         if (function_exists('posix_isatty') && !posix_isatty(1)) {
  18821.             // output is being redirected to a file or through a pipe
  18822.         } elseif ($term) {
  18823.             // XXX can use ncurses extension here, if available
  18824.             if (preg_match('/^(xterm|vt220|linux)/', $term)) {
  18825.                 $this->term['bold'] = sprintf("%c%c%c%c", 27, 91, 49, 109);
  18826.                 $this->term['normal']=sprintf("%c%c%c", 27, 91, 109);
  18827.             } elseif (preg_match('/^vt100/', $term)) {
  18828.                 $this->term['bold'] = sprintf("%c%c%c%c%c%c", 27, 91, 49, 109, 0, 0);
  18829.                 $this->term['normal']=sprintf("%c%c%c%c%c", 27, 91, 109, 0, 0);
  18830.             }
  18831.         } elseif (OS_WINDOWS) {
  18832.             // XXX add ANSI codes here
  18833.         }
  18834.     }
  18835.  
  18836.     // }}}
  18837.  
  18838.     // {{{ displayLine(text)
  18839.  
  18840.     function displayLine($text)
  18841.     {
  18842.         trigger_error("PEAR_Frontend_CLI::displayLine deprecated", E_USER_ERROR);
  18843.     }
  18844.  
  18845.     function _displayLine($text)
  18846.     {
  18847.         print "$this->lp$text\n";
  18848.     }
  18849.  
  18850.     // }}}
  18851.     // {{{ display(text)
  18852.  
  18853.     function display($text)
  18854.     {
  18855.         trigger_error("PEAR_Frontend_CLI::display deprecated", E_USER_ERROR);
  18856.     }
  18857.  
  18858.     function _display($text)
  18859.     {
  18860.         print $text;
  18861.     }
  18862.  
  18863.     // }}}
  18864.     // {{{ displayError(eobj)
  18865.  
  18866.     /**
  18867.      * @param object PEAR_Error object
  18868.      */
  18869.     function displayError($eobj)
  18870.     {
  18871.         return $this->_displayLine($eobj->getMessage());
  18872.     }
  18873.  
  18874.     // }}}
  18875.     // {{{ displayFatalError(eobj)
  18876.  
  18877.     /**
  18878.      * @param object PEAR_Error object
  18879.      */
  18880.     function displayFatalError($eobj)
  18881.     {
  18882.         $this->displayError($eobj);
  18883.         if (class_exists('PEAR_Config')) {
  18884.             $config = &PEAR_Config::singleton();
  18885.             if ($config->get('verbose') > 5) {
  18886.                 if (function_exists('debug_print_backtrace')) {
  18887.                     debug_print_backtrace();
  18888.                 } elseif (function_exists('debug_backtrace')) {
  18889.                     $trace = debug_backtrace();
  18890.                     $raised = false;
  18891.                     foreach ($trace as $i => $frame) {
  18892.                         if (!$raised) {
  18893.                             if (isset($frame['class']) && strtolower($frame['class']) ==
  18894.                                   'pear' && strtolower($frame['function']) == 'raiseerror') {
  18895.                                 $raised = true;
  18896.                             } else {
  18897.                                 continue;
  18898.                             }
  18899.                         }
  18900.                         if (!isset($frame['class'])) {
  18901.                             $frame['class'] = '';
  18902.                         }
  18903.                         if (!isset($frame['type'])) {
  18904.                             $frame['type'] = '';
  18905.                         }
  18906.                         if (!isset($frame['function'])) {
  18907.                             $frame['function'] = '';
  18908.                         }
  18909.                         if (!isset($frame['line'])) {
  18910.                             $frame['line'] = '';
  18911.                         }
  18912.                         $this->_displayLine("#$i: $frame[class]$frame[type]$frame[function] $frame[line]");
  18913.                     }
  18914.                 }
  18915.             }
  18916.         }
  18917.         exit(1);
  18918.     }
  18919.  
  18920.     // }}}
  18921.     // {{{ displayHeading(title)
  18922.  
  18923.     function displayHeading($title)
  18924.     {
  18925.         trigger_error("PEAR_Frontend_CLI::displayHeading deprecated", E_USER_ERROR);
  18926.     }
  18927.  
  18928.     function _displayHeading($title)
  18929.     {
  18930.         print $this->lp.$this->bold($title)."\n";
  18931.         print $this->lp.str_repeat("=", strlen($title))."\n";
  18932.     }
  18933.  
  18934.     // }}}
  18935.  
  18936.     /**
  18937.      * Instruct the runInstallScript method to skip a paramgroup that matches the
  18938.      * id value passed in.
  18939.      *
  18940.      * This method is useful for dynamically configuring which sections of a post-install script
  18941.      * will be run based on the user's setup, which is very useful for making flexible
  18942.      * post-install scripts without losing the cross-Frontend ability to retrieve user input
  18943.      * @param string
  18944.      */
  18945.     function skipParamgroup($id)
  18946.     {
  18947.         $this->_skipSections[$id] = true;
  18948.     }
  18949.  
  18950.     function runPostinstallScripts(&$scripts)
  18951.     {
  18952.         foreach ($scripts as $i => $script) {
  18953.             $this->runInstallScript($scripts[$i]->_params, $scripts[$i]->_obj);
  18954.         }
  18955.     }
  18956.  
  18957.     /**
  18958.      * @param array $xml contents of postinstallscript tag
  18959.      * @param object $script post-installation script
  18960.      * @param string install|upgrade
  18961.      */
  18962.     function runInstallScript($xml, &$script)
  18963.     {
  18964.         $this->_skipSections = array();
  18965.         if (!is_array($xml) || !isset($xml['paramgroup'])) {
  18966.             $script->run(array(), '_default');
  18967.         } else {
  18968.             $completedPhases = array();
  18969.             if (!isset($xml['paramgroup'][0])) {
  18970.                 $xml['paramgroup'] = array($xml['paramgroup']);
  18971.             }
  18972.             foreach ($xml['paramgroup'] as $group) {
  18973.                 if (isset($this->_skipSections[$group['id']])) {
  18974.                     // the post-install script chose to skip this section dynamically
  18975.                     continue;
  18976.                 }
  18977.                 if (isset($group['name'])) {
  18978.                     $paramname = explode('::', $group['name']);
  18979.                     if ($lastgroup['id'] != $paramname[0]) {
  18980.                         continue;
  18981.                     }
  18982.                     $group['name'] = $paramname[1];
  18983.                     if (isset($answers)) {
  18984.                         if (isset($answers[$group['name']])) {
  18985.                             switch ($group['conditiontype']) {
  18986.                                 case '=' :
  18987.                                     if ($answers[$group['name']] != $group['value']) {
  18988.                                         continue 2;
  18989.                                     }
  18990.                                 break;
  18991.                                 case '!=' :
  18992.                                     if ($answers[$group['name']] == $group['value']) {
  18993.                                         continue 2;
  18994.                                     }
  18995.                                 break;
  18996.                                 case 'preg_match' :
  18997.                                     if (!@preg_match('/' . $group['value'] . '/',
  18998.                                           $answers[$group['name']])) {
  18999.                                         continue 2;
  19000.                                     }
  19001.                                 break;
  19002.                                 default :
  19003.                                 return;
  19004.                             }
  19005.                         }
  19006.                     } else {
  19007.                         return;
  19008.                     }
  19009.                 }
  19010.                 $lastgroup = $group;
  19011.                 if (isset($group['instructions'])) {
  19012.                     $this->_display($group['instructions']);
  19013.                 }
  19014.                 if (!isset($group['param'][0])) {
  19015.                     $group['param'] = array($group['param']);
  19016.                 }
  19017.                 if (isset($group['param'])) {
  19018.                     if (method_exists($script, 'postProcessPrompts')) {
  19019.                         $prompts = $script->postProcessPrompts($group['param'], $group['id']);
  19020.                         if (!is_array($prompts) || count($prompts) != count($group['param'])) {
  19021.                             $this->outputData('postinstall', 'Error: post-install script did not ' .
  19022.                                 'return proper post-processed prompts');
  19023.                             $prompts = $group['param'];
  19024.                         } else {
  19025.                             foreach ($prompts as $i => $var) {
  19026.                                 if (!is_array($var) || !isset($var['prompt']) ||
  19027.                                       !isset($var['name']) ||
  19028.                                       ($var['name'] != $group['param'][$i]['name']) ||
  19029.                                       ($var['type'] != $group['param'][$i]['type'])) {
  19030.                                     $this->outputData('postinstall', 'Error: post-install script ' .
  19031.                                         'modified the variables or prompts, severe security risk. ' .
  19032.                                         'Will instead use the defaults from the package.xml');
  19033.                                     $prompts = $group['param'];
  19034.                                 }
  19035.                             }
  19036.                         }
  19037.                         $answers = $this->confirmDialog($prompts);
  19038.                     } else {
  19039.                         $answers = $this->confirmDialog($group['param']);
  19040.                     }
  19041.                 }
  19042.                 if ((isset($answers) && $answers) || !isset($group['param'])) {
  19043.                     if (!isset($answers)) {
  19044.                         $answers = array();
  19045.                     }
  19046.                     array_unshift($completedPhases, $group['id']);
  19047.                     if (!$script->run($answers, $group['id'])) {
  19048.                         $script->run($completedPhases, '_undoOnError');
  19049.                         return;
  19050.                     }
  19051.                 } else {
  19052.                     $script->run($completedPhases, '_undoOnError');
  19053.                     return;
  19054.                 }
  19055.             }
  19056.         }
  19057.     }
  19058.  
  19059.     /**
  19060.      * Ask for user input, confirm the answers and continue until the user is satisfied
  19061.      * @param array an array of arrays, format array('name' => 'paramname', 'prompt' =>
  19062.      *              'text to display', 'type' => 'string'[, default => 'default value'])
  19063.      * @return array
  19064.      */
  19065.     function confirmDialog($params)
  19066.     {
  19067.         $answers = array();
  19068.         $prompts = $types = array();
  19069.         foreach ($params as $param) {
  19070.             $prompts[$param['name']] = $param['prompt'];
  19071.             $types[$param['name']] = $param['type'];
  19072.             if (isset($param['default'])) {
  19073.                 $answers[$param['name']] = $param['default'];
  19074.             } else {
  19075.                 $answers[$param['name']] = '';
  19076.             }
  19077.         }
  19078.         $tried = false;
  19079.         do {
  19080.             if ($tried) {
  19081.                 $i = 1;
  19082.                 foreach ($answers as $var => $value) {
  19083.                     if (!strlen($value)) {
  19084.                         echo $this->bold("* Enter an answer for #" . $i . ": ({$prompts[$var]})\n");
  19085.                     }
  19086.                     $i++;
  19087.                 }
  19088.             }
  19089.             $answers = $this->userDialog('', $prompts, $types, $answers);
  19090.             $tried = true;
  19091.         } while (is_array($answers) && count(array_filter($answers)) != count($prompts));
  19092.         return $answers;
  19093.     }
  19094.     // {{{ userDialog(prompt, [type], [default])
  19095.  
  19096.     function userDialog($command, $prompts, $types = array(), $defaults = array(),
  19097.                         $screensize = 20)
  19098.     {
  19099.         if (!is_array($prompts)) {
  19100.             return array();
  19101.         }
  19102.         $testprompts = array_keys($prompts);
  19103.         $result = $defaults;
  19104.         if (!defined('STDIN')) {
  19105.             $fp = fopen('php://stdin', 'r');
  19106.         } else {
  19107.             $fp = STDIN;
  19108.         }
  19109.         reset($prompts);
  19110.         if (count($prompts) == 1 && $types[key($prompts)] == 'yesno') {
  19111.             foreach ($prompts as $key => $prompt) {
  19112.                 $type = $types[$key];
  19113.                 $default = @$defaults[$key];
  19114.                 print "$prompt ";
  19115.                 if ($default) {
  19116.                     print "[$default] ";
  19117.                 }
  19118.                 print ": ";
  19119.                 if (version_compare(phpversion(), '5.0.0', '<')) {
  19120.                     $line = fgets($fp, 2048);
  19121.                 } else {
  19122.                     if (!defined('STDIN')) {
  19123.                         define('STDIN', fopen('php://stdin', 'r'));
  19124.                     }
  19125.                     $line = fgets(STDIN, 2048);
  19126.                 }
  19127.                 if ($default && trim($line) == "") {
  19128.                     $result[$key] = $default;
  19129.                 } else {
  19130.                     $result[$key] = trim($line);
  19131.                 }
  19132.             }
  19133.             return $result;
  19134.         }
  19135.         while (true) {
  19136.             $descLength = max(array_map('strlen', $prompts));
  19137.             $descFormat = "%-{$descLength}s";
  19138.             $last = count($prompts);
  19139.  
  19140.             $i = 0;
  19141.             foreach ($prompts as $n => $var) {
  19142.                 printf("%2d. $descFormat : %s\n", ++$i, $prompts[$n], isset($result[$n]) ?
  19143.                     $result[$n] : null);
  19144.             }
  19145.  
  19146.             print "\n1-$last, 'all', 'abort', or Enter to continue: ";
  19147.             $tmp = trim(fgets($fp, 1024));
  19148.             if (empty($tmp)) {
  19149.                 break;
  19150.             }
  19151.             if ($tmp == 'abort') {
  19152.                 return false;
  19153.             }
  19154.             if (isset($testprompts[(int)$tmp - 1])) {
  19155.                 $var = $testprompts[(int)$tmp - 1];
  19156.                 $desc = $prompts[$var];
  19157.                 $current = @$result[$var];
  19158.                 print "$desc [$current] : ";
  19159.                 $tmp = trim(fgets($fp, 1024));
  19160.                 if (trim($tmp) !== '') {
  19161.                     $result[$var] = trim($tmp);
  19162.                 }
  19163.             } elseif ($tmp == 'all') {
  19164.                 foreach ($prompts as $var => $desc) {
  19165.                     $current = $result[$var];
  19166.                     print "$desc [$current] : ";
  19167.                     $tmp = trim(fgets($fp, 1024));
  19168.                     if (trim($tmp) !== '') {
  19169.                         $result[$var] = trim($tmp);
  19170.                     }
  19171.                 }
  19172.             }
  19173.         }
  19174.         if (!defined('STDIN')) {
  19175.             fclose($fp);
  19176.         }
  19177.         return $result;
  19178.     }
  19179.  
  19180.     // }}}
  19181.     // {{{ userConfirm(prompt, [default])
  19182.  
  19183.     function userConfirm($prompt, $default = 'yes')
  19184.     {
  19185.         trigger_error("PEAR_Frontend_CLI::userConfirm not yet converted", E_USER_ERROR);
  19186.         static $positives = array('y', 'yes', 'on', '1');
  19187.         static $negatives = array('n', 'no', 'off', '0');
  19188.         print "$this->lp$prompt [$default] : ";
  19189.         $fp = fopen("php://stdin", "r");
  19190.         $line = fgets($fp, 2048);
  19191.         fclose($fp);
  19192.         $answer = strtolower(trim($line));
  19193.         if (empty($answer)) {
  19194.             $answer = $default;
  19195.         }
  19196.         if (in_array($answer, $positives)) {
  19197.             return true;
  19198.         }
  19199.         if (in_array($answer, $negatives)) {
  19200.             return false;
  19201.         }
  19202.         if (in_array($default, $positives)) {
  19203.             return true;
  19204.         }
  19205.         return false;
  19206.     }
  19207.  
  19208.     // }}}
  19209.     // {{{ startTable([params])
  19210.  
  19211.     function startTable($params = array())
  19212.     {
  19213.         trigger_error("PEAR_Frontend_CLI::startTable deprecated", E_USER_ERROR);
  19214.     }
  19215.  
  19216.     function _startTable($params = array())
  19217.     {
  19218.         $params['table_data'] = array();
  19219.         $params['widest'] = array();  // indexed by column
  19220.         $params['highest'] = array(); // indexed by row
  19221.         $params['ncols'] = 0;
  19222.         $this->params = $params;
  19223.     }
  19224.  
  19225.     // }}}
  19226.     // {{{ tableRow(columns, [rowparams], [colparams])
  19227.  
  19228.     function tableRow($columns, $rowparams = array(), $colparams = array())
  19229.     {
  19230.         trigger_error("PEAR_Frontend_CLI::tableRow deprecated", E_USER_ERROR);
  19231.     }
  19232.  
  19233.     function _tableRow($columns, $rowparams = array(), $colparams = array())
  19234.     {
  19235.         $highest = 1;
  19236.         for ($i = 0; $i < sizeof($columns); $i++) {
  19237.             $col = &$columns[$i];
  19238.             if (isset($colparams[$i]) && !empty($colparams[$i]['wrap'])) {
  19239.                 $col = wordwrap($col, $colparams[$i]['wrap'], "\n", 0);
  19240.             }
  19241.             if (strpos($col, "\n") !== false) {
  19242.                 $multiline = explode("\n", $col);
  19243.                 $w = 0;
  19244.                 foreach ($multiline as $n => $line) {
  19245.                     if (strlen($line) > $w) {
  19246.                         $w = strlen($line);
  19247.                     }
  19248.                 }
  19249.                 $lines = sizeof($multiline);
  19250.             } else {
  19251.                 $w = strlen($col);
  19252.             }
  19253.  
  19254.             if (isset($this->params['widest'][$i])) {
  19255.                 if ($w > $this->params['widest'][$i]) {
  19256.                     $this->params['widest'][$i] = $w;
  19257.                 }
  19258.             } else {
  19259.                 $this->params['widest'][$i] = $w;
  19260.             }
  19261.             $tmp = count_chars($columns[$i], 1);
  19262.             // handle unix, mac and windows formats
  19263.             $lines = (isset($tmp[10]) ? $tmp[10] : (isset($tmp[13]) ? $tmp[13] : 0)) + 1;
  19264.             if ($lines > $highest) {
  19265.                 $highest = $lines;
  19266.             }
  19267.         }
  19268.         if (sizeof($columns) > $this->params['ncols']) {
  19269.             $this->params['ncols'] = sizeof($columns);
  19270.         }
  19271.         $new_row = array(
  19272.             'data' => $columns,
  19273.             'height' => $highest,
  19274.             'rowparams' => $rowparams,
  19275.             'colparams' => $colparams,
  19276.             );
  19277.         $this->params['table_data'][] = $new_row;
  19278.     }
  19279.  
  19280.     // }}}
  19281.     // {{{ endTable()
  19282.  
  19283.     function endTable()
  19284.     {
  19285.         trigger_error("PEAR_Frontend_CLI::endTable deprecated", E_USER_ERROR);
  19286.     }
  19287.  
  19288.     function _endTable()
  19289.     {
  19290.         extract($this->params);
  19291.         if (!empty($caption)) {
  19292.             $this->_displayHeading($caption);
  19293.         }
  19294.         if (count($table_data) == 0) {
  19295.             return;
  19296.         }
  19297.         if (!isset($width)) {
  19298.             $width = $widest;
  19299.         } else {
  19300.             for ($i = 0; $i < $ncols; $i++) {
  19301.                 if (!isset($width[$i])) {
  19302.                     $width[$i] = $widest[$i];
  19303.                 }
  19304.             }
  19305.         }
  19306.         $border = false;
  19307.         if (empty($border)) {
  19308.             $cellstart = '';
  19309.             $cellend = ' ';
  19310.             $rowend = '';
  19311.             $padrowend = false;
  19312.             $borderline = '';
  19313.         } else {
  19314.             $cellstart = '| ';
  19315.             $cellend = ' ';
  19316.             $rowend = '|';
  19317.             $padrowend = true;
  19318.             $borderline = '+';
  19319.             foreach ($width as $w) {
  19320.                 $borderline .= str_repeat('-', $w + strlen($cellstart) + strlen($cellend) - 1);
  19321.                 $borderline .= '+';
  19322.             }
  19323.         }
  19324.         if ($borderline) {
  19325.             $this->_displayLine($borderline);
  19326.         }
  19327.         for ($i = 0; $i < sizeof($table_data); $i++) {
  19328.             extract($table_data[$i]);
  19329.             if (!is_array($rowparams)) {
  19330.                 $rowparams = array();
  19331.             }
  19332.             if (!is_array($colparams)) {
  19333.                 $colparams = array();
  19334.             }
  19335.             $rowlines = array();
  19336.             if ($height > 1) {
  19337.                 for ($c = 0; $c < sizeof($data); $c++) {
  19338.                     $rowlines[$c] = preg_split('/(\r?\n|\r)/', $data[$c]);
  19339.                     if (sizeof($rowlines[$c]) < $height) {
  19340.                         $rowlines[$c] = array_pad($rowlines[$c], $height, '');
  19341.                     }
  19342.                 }
  19343.             } else {
  19344.                 for ($c = 0; $c < sizeof($data); $c++) {
  19345.                     $rowlines[$c] = array($data[$c]);
  19346.                 }
  19347.             }
  19348.             for ($r = 0; $r < $height; $r++) {
  19349.                 $rowtext = '';
  19350.                 for ($c = 0; $c < sizeof($data); $c++) {
  19351.                     if (isset($colparams[$c])) {
  19352.                         $attribs = array_merge($rowparams, $colparams);
  19353.                     } else {
  19354.                         $attribs = $rowparams;
  19355.                     }
  19356.                     $w = isset($width[$c]) ? $width[$c] : 0;
  19357.                     //$cell = $data[$c];
  19358.                     $cell = $rowlines[$c][$r];
  19359.                     $l = strlen($cell);
  19360.                     if ($l > $w) {
  19361.                         $cell = substr($cell, 0, $w);
  19362.                     }
  19363.                     if (isset($attribs['bold'])) {
  19364.                         $cell = $this->bold($cell);
  19365.                     }
  19366.                     if ($l < $w) {
  19367.                         // not using str_pad here because we may
  19368.                         // add bold escape characters to $cell
  19369.                         $cell .= str_repeat(' ', $w - $l);
  19370.                     }
  19371.  
  19372.                     $rowtext .= $cellstart . $cell . $cellend;
  19373.                 }
  19374.                 if (!$border) {
  19375.                     $rowtext = rtrim($rowtext);
  19376.                 }
  19377.                 $rowtext .= $rowend;
  19378.                 $this->_displayLine($rowtext);
  19379.             }
  19380.         }
  19381.         if ($borderline) {
  19382.             $this->_displayLine($borderline);
  19383.         }
  19384.     }
  19385.  
  19386.     // }}}
  19387.     // {{{ outputData()
  19388.  
  19389.     function outputData($data, $command = '_default')
  19390.     {
  19391.         switch ($command) {
  19392.             case 'channel-info':
  19393.                 foreach ($data as $type => $section) {
  19394.                     if ($type == 'main') {
  19395.                         $section['data'] = array_values($section['data']);
  19396.                     }
  19397.                     $this->outputData($section);
  19398.                 }
  19399.                 break;
  19400.             case 'install':
  19401.             case 'upgrade':
  19402.             case 'upgrade-all':
  19403.                 if (isset($data['release_warnings'])) {
  19404.                     $this->_displayLine('');
  19405.                     $this->_startTable(array(
  19406.                         'border' => false,
  19407.                         'caption' => 'Release Warnings'
  19408.                         ));
  19409.                     $this->_tableRow(array($data['release_warnings']), null, array(1 => array('wrap' => 55)));
  19410.                     $this->_endTable();
  19411.                     $this->_displayLine('');
  19412.                 }
  19413.                 $this->_displayLine($data['data']);
  19414.                 break;
  19415.             case 'search':
  19416.                 $this->_startTable($data);
  19417.                 if (isset($data['headline']) && is_array($data['headline'])) {
  19418.                     $this->_tableRow($data['headline'], array('bold' => true), array(1 => array('wrap' => 55)));
  19419.                 }
  19420.  
  19421.                 foreach($data['data'] as $category) {
  19422.                     foreach($category as $pkg) {
  19423.                         $this->_tableRow($pkg, null, array(1 => array('wrap' => 55)));
  19424.                     }
  19425.                 };
  19426.                 $this->_endTable();
  19427.                 break;
  19428.             case 'list-all':
  19429.                 if (!isset($data['data'])) {
  19430.                       $this->_displayLine('No packages in channel');
  19431.                       break;
  19432.                 }
  19433.                 $this->_startTable($data);
  19434.                 if (isset($data['headline']) && is_array($data['headline'])) {
  19435.                     $this->_tableRow($data['headline'], array('bold' => true), array(1 => array('wrap' => 55)));
  19436.                 }
  19437.  
  19438.                 foreach($data['data'] as $category) {
  19439.                     foreach($category as $pkg) {
  19440.                         unset($pkg[4]);
  19441.                         unset($pkg[5]);
  19442.                         $this->_tableRow($pkg, null, array(1 => array('wrap' => 55)));
  19443.                     }
  19444.                 };
  19445.                 $this->_endTable();
  19446.                 break;
  19447.             case 'config-show':
  19448.                 $data['border'] = false;
  19449.                 $opts = array(0 => array('wrap' => 30),
  19450.                               1 => array('wrap' => 20),
  19451.                               2 => array('wrap' => 35));
  19452.                 $this->_startTable($data);
  19453.                 if (isset($data['headline']) && is_array($data['headline'])) {
  19454.                     $this->_tableRow($data['headline'],
  19455.                                      array('bold' => true),
  19456.                                      $opts);
  19457.                 }
  19458.                 foreach($data['data'] as $group) {
  19459.                     foreach($group as $value) {
  19460.                         if ($value[2] == '') {
  19461.                             $value[2] = "<not set>";
  19462.                         }
  19463.                         $this->_tableRow($value, null, $opts);
  19464.                     }
  19465.                 }
  19466.                 $this->_endTable();
  19467.                 break;
  19468.             case 'remote-info':
  19469.                 $d = $data;
  19470.                 $data = array(
  19471.                     'caption' => 'Package details:',
  19472.                     'border' => false,
  19473.                     'data' => array(
  19474.                         array("Latest",    $data['stable']),
  19475.                         array("Installed", $data['installed']),
  19476.                         array("Package",   $data['name']),
  19477.                         array("License",   $data['license']),
  19478.                         array("Category",  $data['category']),
  19479.                         array("Summary",   $data['summary']),
  19480.                         array("Description", $data['description']),
  19481.                         ),
  19482.                     );
  19483.                     if (isset($d['deprecated']) && $d['deprecated']) {
  19484.                         $conf = &PEAR_Config::singleton();
  19485.                         $reg = $conf->getRegistry();
  19486.                         $name = $reg->parsedPackageNameToString($d['deprecated'], true);
  19487.                         $data['data'][] = array('Deprecated! use', $name);
  19488.                     }
  19489.             default: {
  19490.                 if (is_array($data)) {
  19491.                     $this->_startTable($data);
  19492.                     $count = count($data['data'][0]);
  19493.                     if ($count == 2) {
  19494.                         $opts = array(0 => array('wrap' => 25),
  19495.                                       1 => array('wrap' => 48)
  19496.                         );
  19497.                     } elseif ($count == 3) {
  19498.                         $opts = array(0 => array('wrap' => 30),
  19499.                                       1 => array('wrap' => 20),
  19500.                                       2 => array('wrap' => 35)
  19501.                         );
  19502.                     } else {
  19503.                         $opts = null;
  19504.                     }
  19505.                     if (isset($data['headline']) && is_array($data['headline'])) {
  19506.                         $this->_tableRow($data['headline'],
  19507.                                          array('bold' => true),
  19508.                                          $opts);
  19509.                     }
  19510.                     foreach($data['data'] as $row) {
  19511.                         $this->_tableRow($row, null, $opts);
  19512.                     }
  19513.                     $this->_endTable();
  19514.                 } else {
  19515.                     $this->_displayLine($data);
  19516.                 }
  19517.             }
  19518.         }
  19519.     }
  19520.  
  19521.     // }}}
  19522.     // {{{ log(text)
  19523.  
  19524.  
  19525.     function log($text, $append_crlf = true)
  19526.     {
  19527.         if ($append_crlf) {
  19528.             return $this->_displayLine($text);
  19529.         }
  19530.         return $this->_display($text);
  19531.     }
  19532.  
  19533.  
  19534.     // }}}
  19535.     // {{{ bold($text)
  19536.  
  19537.     function bold($text)
  19538.     {
  19539.         if (empty($this->term['bold'])) {
  19540.             return strtoupper($text);
  19541.         }
  19542.         return $this->term['bold'] . $text . $this->term['normal'];
  19543.     }
  19544.  
  19545.     // }}}
  19546. }
  19547.  
  19548. ?>
  19549. package.xml100644   1750   1750       13604 10547623416   6451 <?xml version="1.0" encoding="UTF-8"?>
  19550. <package packagerversion="1.5.0RC2" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
  19551.  <name>Archive_Tar</name>
  19552.  <channel>pear.php.net</channel>
  19553.  <summary>Tar file management class</summary>
  19554.  <description>This class provides handling of tar files in PHP.
  19555. It supports creating, listing, extracting and adding to tar files.
  19556. Gzip support is available if PHP has the zlib extension built-in or
  19557. loaded. Bz2 compression is also supported with the bz2 extension loaded.</description>
  19558.  <lead>
  19559.   <name>Gregory Beaver</name>
  19560.   <user>cellog</user>
  19561.   <email>cellog@php.net</email>
  19562.   <active>yes</active>
  19563.  </lead>
  19564.  <lead>
  19565.   <name>Vincent Blavet</name>
  19566.   <user>vblavet</user>
  19567.   <email>vincent@phpconcept.net</email>
  19568.   <active>no</active>
  19569.  </lead>
  19570.  <helper>
  19571.   <name>Stig Bakken</name>
  19572.   <user>ssb</user>
  19573.   <email>stig@php.net</email>
  19574.   <active>no</active>
  19575.  </helper>
  19576.  <date>2007-01-05</date>
  19577.  <time>22:35:26</time>
  19578.  <version>
  19579.   <release>1.3.2</release>
  19580.   <api>1.3.2</api>
  19581.  </version>
  19582.  <stability>
  19583.   <release>stable</release>
  19584.   <api>stable</api>
  19585.  </stability>
  19586.  <license uri="http://www.php.net/license">PHP License</license>
  19587.  <notes>Correct Bug #4016
  19588. Remove duplicate remove error display with '@'
  19589. Correct Bug #3909 : Check existence of OS_WINDOWS constant
  19590. Correct Bug #5452 fix for "lone zero block" when untarring packages
  19591. Change filemode (from pear-core/Archive/Tar.php v.1.21)
  19592. Correct Bug #6486 Can not extract symlinks
  19593. Correct Bug #6933 Archive_Tar (Tar file management class) Directory traversal    
  19594. Correct Bug #8114 Files added on-the-fly not storing date
  19595. Correct Bug #9352 Bug on _dirCheck function over nfs path</notes>
  19596.  <contents>
  19597.   <dir name="/">
  19598.    <file baseinstalldir="/" md5sum="06409d39f4268a9aa9e2924c7f397a38" name="Archive/Tar.php" role="php" />
  19599.    <file baseinstalldir="/" md5sum="29b03715377b18b1fafcff98a99cc9a7" name="docs/Archive_Tar.txt" role="doc" />
  19600.   </dir>
  19601.  </contents>
  19602.  <compatible>
  19603.   <name>PEAR</name>
  19604.   <channel>pear.php.net</channel>
  19605.   <min>1.4.0</min>
  19606.   <max>1.5.0RC2</max>
  19607.  </compatible>
  19608.  <dependencies>
  19609.   <required>
  19610.    <php>
  19611.     <min>4.0.0</min>
  19612.    </php>
  19613.    <pearinstaller>
  19614.     <min>1.4.0b1</min>
  19615.    </pearinstaller>
  19616.   </required>
  19617.  </dependencies>
  19618.  <phprelease />
  19619.  <changelog>
  19620.   <release>
  19621.    <version>
  19622.     <release>1.3.1</release>
  19623.     <api>1.3.1</api>
  19624.    </version>
  19625.    <stability>
  19626.     <release>stable</release>
  19627.     <api>stable</api>
  19628.    </stability>
  19629.    <date>2005-03-17</date>
  19630.    <license uri="http://www.php.net/license">PHP License</license>
  19631.    <notes>Correct Bug #3855</notes>
  19632.   </release>
  19633.   <release>
  19634.    <version>
  19635.     <release>1.3.0</release>
  19636.     <api>1.3.0</api>
  19637.    </version>
  19638.    <stability>
  19639.     <release>stable</release>
  19640.     <api>stable</api>
  19641.    </stability>
  19642.    <date>2005-03-06</date>
  19643.    <license uri="http://www.php.net/license">PHP License</license>
  19644.    <notes>Bugs correction (2475, 2488, 2135, 2176)</notes>
  19645.   </release>
  19646.   <release>
  19647.    <version>
  19648.     <release>1.2</release>
  19649.     <api>1.2</api>
  19650.    </version>
  19651.    <stability>
  19652.     <release>stable</release>
  19653.     <api>stable</api>
  19654.    </stability>
  19655.    <date>2004-05-08</date>
  19656.    <license uri="http://www.php.net/license">PHP License</license>
  19657.    <notes>Add support for other separator than the space char and bug
  19658.     correction</notes>
  19659.   </release>
  19660.   <release>
  19661.    <version>
  19662.     <release>1.1</release>
  19663.     <api>1.1</api>
  19664.    </version>
  19665.    <stability>
  19666.     <release>stable</release>
  19667.     <api>stable</api>
  19668.    </stability>
  19669.    <date>2003-05-28</date>
  19670.    <license uri="http://www.php.net/license">PHP License</license>
  19671.    <notes>* Add support for BZ2 compression
  19672. * Add support for add and extract without using temporary files : methods addString() and extractInString()</notes>
  19673.   </release>
  19674.   <release>
  19675.    <version>
  19676.     <release>1.0</release>
  19677.     <api>1.0</api>
  19678.    </version>
  19679.    <stability>
  19680.     <release>stable</release>
  19681.     <api>stable</api>
  19682.    </stability>
  19683.    <date>2003-01-24</date>
  19684.    <license uri="http://www.php.net/license">PHP License</license>
  19685.    <notes>Change status to stable</notes>
  19686.   </release>
  19687.   <release>
  19688.    <version>
  19689.     <release>0.10-b1</release>
  19690.     <api>0.10-b1</api>
  19691.    </version>
  19692.    <stability>
  19693.     <release>beta</release>
  19694.     <api>beta</api>
  19695.    </stability>
  19696.    <date>2003-01-08</date>
  19697.    <license uri="http://www.php.net/license">PHP License</license>
  19698.    <notes>Add support for long filenames (greater than 99 characters)</notes>
  19699.   </release>
  19700.   <release>
  19701.    <version>
  19702.     <release>0.9</release>
  19703.     <api>0.9</api>
  19704.    </version>
  19705.    <stability>
  19706.     <release>stable</release>
  19707.     <api>stable</api>
  19708.    </stability>
  19709.    <date>2002-05-27</date>
  19710.    <license uri="http://www.php.net/license">PHP License</license>
  19711.    <notes>Auto-detect gzip'ed files</notes>
  19712.   </release>
  19713.   <release>
  19714.    <version>
  19715.     <release>0.4</release>
  19716.     <api>0.4</api>
  19717.    </version>
  19718.    <stability>
  19719.     <release>stable</release>
  19720.     <api>stable</api>
  19721.    </stability>
  19722.    <date>2002-05-20</date>
  19723.    <license uri="http://www.php.net/license">PHP License</license>
  19724.    <notes>Windows bugfix: use forward slashes inside archives</notes>
  19725.   </release>
  19726.   <release>
  19727.    <version>
  19728.     <release>0.2</release>
  19729.     <api>0.2</api>
  19730.    </version>
  19731.    <stability>
  19732.     <release>stable</release>
  19733.     <api>stable</api>
  19734.    </stability>
  19735.    <date>2002-02-18</date>
  19736.    <license uri="http://www.php.net/license">PHP License</license>
  19737.    <notes>From initial commit to stable</notes>
  19738.   </release>
  19739.   <release>
  19740.    <version>
  19741.     <release>0.3</release>
  19742.     <api>0.3</api>
  19743.    </version>
  19744.    <stability>
  19745.     <release>stable</release>
  19746.     <api>stable</api>
  19747.    </stability>
  19748.    <date>2002-04-13</date>
  19749.    <license uri="http://www.php.net/license">PHP License</license>
  19750.    <notes>Windows bugfix: used wrong directory separators</notes>
  19751.   </release>
  19752.  </changelog>
  19753. </package>
  19754. Archive_Tar-1.3.2/Archive/Tar.php100644   1750   1750      167330 10547623416  12030 <?php
  19755. /* vim: set ts=4 sw=4: */
  19756. // +----------------------------------------------------------------------+
  19757. // | PHP Version 4                                                        |
  19758. // +----------------------------------------------------------------------+
  19759. // | Copyright (c) 1997-2003 The PHP Group                                |
  19760. // +----------------------------------------------------------------------+
  19761. // | This source file is subject to version 3.0 of the PHP license,       |
  19762. // | that is bundled with this package in the file LICENSE, and is        |
  19763. // | available through the world-wide-web at the following url:           |
  19764. // | http://www.php.net/license/3_0.txt.                                  |
  19765. // | If you did not receive a copy of the PHP license and are unable to   |
  19766. // | obtain it through the world-wide-web, please send a note to          |
  19767. // | license@php.net so we can mail you a copy immediately.               |
  19768. // +----------------------------------------------------------------------+
  19769. // | Author: Vincent Blavet <vincent@phpconcept.net>                      |
  19770. // +----------------------------------------------------------------------+
  19771. //
  19772. // $Id: Tar.php,v 1.39 2006/12/22 19:20:08 cellog Exp $
  19773.  
  19774. require_once 'PEAR.php';
  19775.  
  19776.  
  19777. define ('ARCHIVE_TAR_ATT_SEPARATOR', 90001);
  19778. define ('ARCHIVE_TAR_END_BLOCK', pack("a512", ''));
  19779.  
  19780. /**
  19781. * Creates a (compressed) Tar archive
  19782. *
  19783. * @author   Vincent Blavet <vincent@phpconcept.net>
  19784. * @version  $Revision: 1.39 $
  19785. * @package  Archive
  19786. */
  19787. class Archive_Tar extends PEAR
  19788. {
  19789.     /**
  19790.     * @var string Name of the Tar
  19791.     */
  19792.     var $_tarname='';
  19793.  
  19794.     /**
  19795.     * @var boolean if true, the Tar file will be gzipped
  19796.     */
  19797.     var $_compress=false;
  19798.  
  19799.     /**
  19800.     * @var string Type of compression : 'none', 'gz' or 'bz2'
  19801.     */
  19802.     var $_compress_type='none';
  19803.  
  19804.     /**
  19805.     * @var string Explode separator
  19806.     */
  19807.     var $_separator=' ';
  19808.  
  19809.     /**
  19810.     * @var file descriptor
  19811.     */
  19812.     var $_file=0;
  19813.  
  19814.     /**
  19815.     * @var string Local Tar name of a remote Tar (http:// or ftp://)
  19816.     */
  19817.     var $_temp_tarname='';
  19818.  
  19819.     // {{{ constructor
  19820.     /**
  19821.     * Archive_Tar Class constructor. This flavour of the constructor only
  19822.     * declare a new Archive_Tar object, identifying it by the name of the
  19823.     * tar file.
  19824.     * If the compress argument is set the tar will be read or created as a
  19825.     * gzip or bz2 compressed TAR file.
  19826.     *
  19827.     * @param    string  $p_tarname  The name of the tar archive to create
  19828.     * @param    string  $p_compress can be null, 'gz' or 'bz2'. This
  19829.     *                   parameter indicates if gzip or bz2 compression
  19830.     *                   is required.  For compatibility reason the
  19831.     *                   boolean value 'true' means 'gz'.
  19832.     * @access public
  19833.     */
  19834.     function Archive_Tar($p_tarname, $p_compress = null)
  19835.     {
  19836.         $this->PEAR();
  19837.         $this->_compress = false;
  19838.         $this->_compress_type = 'none';
  19839.         if (($p_compress === null) || ($p_compress == '')) {
  19840.             if (@file_exists($p_tarname)) {
  19841.                 if ($fp = @fopen($p_tarname, "rb")) {
  19842.                     // look for gzip magic cookie
  19843.                     $data = fread($fp, 2);
  19844.                     fclose($fp);
  19845.                     if ($data == "\37\213") {
  19846.                         $this->_compress = true;
  19847.                         $this->_compress_type = 'gz';
  19848.                     // No sure it's enought for a magic code ....
  19849.                     } elseif ($data == "BZ") {
  19850.                         $this->_compress = true;
  19851.                         $this->_compress_type = 'bz2';
  19852.                     }
  19853.                 }
  19854.             } else {
  19855.                 // probably a remote file or some file accessible
  19856.                 // through a stream interface
  19857.                 if (substr($p_tarname, -2) == 'gz') {
  19858.                     $this->_compress = true;
  19859.                     $this->_compress_type = 'gz';
  19860.                 } elseif ((substr($p_tarname, -3) == 'bz2') ||
  19861.                           (substr($p_tarname, -2) == 'bz')) {
  19862.                     $this->_compress = true;
  19863.                     $this->_compress_type = 'bz2';
  19864.                 }
  19865.             }
  19866.         } else {
  19867.             if (($p_compress === true) || ($p_compress == 'gz')) {
  19868.                 $this->_compress = true;
  19869.                 $this->_compress_type = 'gz';
  19870.             } else if ($p_compress == 'bz2') {
  19871.                 $this->_compress = true;
  19872.                 $this->_compress_type = 'bz2';
  19873.             } else {
  19874.                 die("Unsupported compression type '$p_compress'\n".
  19875.                     "Supported types are 'gz' and 'bz2'.\n");
  19876.                 return false;
  19877.             }
  19878.         }
  19879.         $this->_tarname = $p_tarname;
  19880.         if ($this->_compress) { // assert zlib or bz2 extension support
  19881.             if ($this->_compress_type == 'gz')
  19882.                 $extname = 'zlib';
  19883.             else if ($this->_compress_type == 'bz2')
  19884.                 $extname = 'bz2';
  19885.  
  19886.             if (!extension_loaded($extname)) {
  19887.                 PEAR::loadExtension($extname);
  19888.             }
  19889.             if (!extension_loaded($extname)) {
  19890.                 die("The extension '$extname' couldn't be found.\n".
  19891.                     "Please make sure your version of PHP was built ".
  19892.                     "with '$extname' support.\n");
  19893.                 return false;
  19894.             }
  19895.         }
  19896.     }
  19897.     // }}}
  19898.  
  19899.     // {{{ destructor
  19900.     function _Archive_Tar()
  19901.     {
  19902.         $this->_close();
  19903.         // ----- Look for a local copy to delete
  19904.         if ($this->_temp_tarname != '')
  19905.             @unlink($this->_temp_tarname);
  19906.         $this->_PEAR();
  19907.     }
  19908.     // }}}
  19909.  
  19910.     // {{{ create()
  19911.     /**
  19912.     * This method creates the archive file and add the files / directories
  19913.     * that are listed in $p_filelist.
  19914.     * If a file with the same name exist and is writable, it is replaced
  19915.     * by the new tar.
  19916.     * The method return false and a PEAR error text.
  19917.     * The $p_filelist parameter can be an array of string, each string
  19918.     * representing a filename or a directory name with their path if
  19919.     * needed. It can also be a single string with names separated by a
  19920.     * single blank.
  19921.     * For each directory added in the archive, the files and
  19922.     * sub-directories are also added.
  19923.     * See also createModify() method for more details.
  19924.     *
  19925.     * @param array  $p_filelist An array of filenames and directory names, or a
  19926.     *                           single string with names separated by a single
  19927.     *                           blank space.
  19928.     * @return                   true on success, false on error.
  19929.     * @see createModify()
  19930.     * @access public
  19931.     */
  19932.     function create($p_filelist)
  19933.     {
  19934.         return $this->createModify($p_filelist, '', '');
  19935.     }
  19936.     // }}}
  19937.  
  19938.     // {{{ add()
  19939.     /**
  19940.     * This method add the files / directories that are listed in $p_filelist in
  19941.     * the archive. If the archive does not exist it is created.
  19942.     * The method return false and a PEAR error text.
  19943.     * The files and directories listed are only added at the end of the archive,
  19944.     * even if a file with the same name is already archived.
  19945.     * See also createModify() method for more details.
  19946.     *
  19947.     * @param array  $p_filelist An array of filenames and directory names, or a
  19948.     *                           single string with names separated by a single
  19949.     *                           blank space.
  19950.     * @return                   true on success, false on error.
  19951.     * @see createModify()
  19952.     * @access public
  19953.     */
  19954.     function add($p_filelist)
  19955.     {
  19956.         return $this->addModify($p_filelist, '', '');
  19957.     }
  19958.     // }}}
  19959.  
  19960.     // {{{ extract()
  19961.     function extract($p_path='')
  19962.     {
  19963.         return $this->extractModify($p_path, '');
  19964.     }
  19965.     // }}}
  19966.  
  19967.     // {{{ listContent()
  19968.     function listContent()
  19969.     {
  19970.         $v_list_detail = array();
  19971.  
  19972.         if ($this->_openRead()) {
  19973.             if (!$this->_extractList('', $v_list_detail, "list", '', '')) {
  19974.                 unset($v_list_detail);
  19975.                 $v_list_detail = 0;
  19976.             }
  19977.             $this->_close();
  19978.         }
  19979.  
  19980.         return $v_list_detail;
  19981.     }
  19982.     // }}}
  19983.  
  19984.     // {{{ createModify()
  19985.     /**
  19986.     * This method creates the archive file and add the files / directories
  19987.     * that are listed in $p_filelist.
  19988.     * If the file already exists and is writable, it is replaced by the
  19989.     * new tar. It is a create and not an add. If the file exists and is
  19990.     * read-only or is a directory it is not replaced. The method return
  19991.     * false and a PEAR error text.
  19992.     * The $p_filelist parameter can be an array of string, each string
  19993.     * representing a filename or a directory name with their path if
  19994.     * needed. It can also be a single string with names separated by a
  19995.     * single blank.
  19996.     * The path indicated in $p_remove_dir will be removed from the
  19997.     * memorized path of each file / directory listed when this path
  19998.     * exists. By default nothing is removed (empty path '')
  19999.     * The path indicated in $p_add_dir will be added at the beginning of
  20000.     * the memorized path of each file / directory listed. However it can
  20001.     * be set to empty ''. The adding of a path is done after the removing
  20002.     * of path.
  20003.     * The path add/remove ability enables the user to prepare an archive
  20004.     * for extraction in a different path than the origin files are.
  20005.     * See also addModify() method for file adding properties.
  20006.     *
  20007.     * @param array  $p_filelist     An array of filenames and directory names,
  20008.     *                               or a single string with names separated by
  20009.     *                               a single blank space.
  20010.     * @param string $p_add_dir      A string which contains a path to be added
  20011.     *                               to the memorized path of each element in
  20012.     *                               the list.
  20013.     * @param string $p_remove_dir   A string which contains a path to be
  20014.     *                               removed from the memorized path of each
  20015.     *                               element in the list, when relevant.
  20016.     * @return boolean               true on success, false on error.
  20017.     * @access public
  20018.     * @see addModify()
  20019.     */
  20020.     function createModify($p_filelist, $p_add_dir, $p_remove_dir='')
  20021.     {
  20022.         $v_result = true;
  20023.  
  20024.         if (!$this->_openWrite())
  20025.             return false;
  20026.  
  20027.         if ($p_filelist != '') {
  20028.             if (is_array($p_filelist))
  20029.                 $v_list = $p_filelist;
  20030.             elseif (is_string($p_filelist))
  20031.                 $v_list = explode($this->_separator, $p_filelist);
  20032.             else {
  20033.                 $this->_cleanFile();
  20034.                 $this->_error('Invalid file list');
  20035.                 return false;
  20036.             }
  20037.  
  20038.             $v_result = $this->_addList($v_list, $p_add_dir, $p_remove_dir);
  20039.         }
  20040.  
  20041.         if ($v_result) {
  20042.             $this->_writeFooter();
  20043.             $this->_close();
  20044.         } else
  20045.             $this->_cleanFile();
  20046.  
  20047.         return $v_result;
  20048.     }
  20049.     // }}}
  20050.  
  20051.     // {{{ addModify()
  20052.     /**
  20053.     * This method add the files / directories listed in $p_filelist at the
  20054.     * end of the existing archive. If the archive does not yet exists it
  20055.     * is created.
  20056.     * The $p_filelist parameter can be an array of string, each string
  20057.     * representing a filename or a directory name with their path if
  20058.     * needed. It can also be a single string with names separated by a
  20059.     * single blank.
  20060.     * The path indicated in $p_remove_dir will be removed from the
  20061.     * memorized path of each file / directory listed when this path
  20062.     * exists. By default nothing is removed (empty path '')
  20063.     * The path indicated in $p_add_dir will be added at the beginning of
  20064.     * the memorized path of each file / directory listed. However it can
  20065.     * be set to empty ''. The adding of a path is done after the removing
  20066.     * of path.
  20067.     * The path add/remove ability enables the user to prepare an archive
  20068.     * for extraction in a different path than the origin files are.
  20069.     * If a file/dir is already in the archive it will only be added at the
  20070.     * end of the archive. There is no update of the existing archived
  20071.     * file/dir. However while extracting the archive, the last file will
  20072.     * replace the first one. This results in a none optimization of the
  20073.     * archive size.
  20074.     * If a file/dir does not exist the file/dir is ignored. However an
  20075.     * error text is send to PEAR error.
  20076.     * If a file/dir is not readable the file/dir is ignored. However an
  20077.     * error text is send to PEAR error.
  20078.     *
  20079.     * @param array      $p_filelist     An array of filenames and directory
  20080.     *                                   names, or a single string with names
  20081.     *                                   separated by a single blank space.
  20082.     * @param string     $p_add_dir      A string which contains a path to be
  20083.     *                                   added to the memorized path of each
  20084.     *                                   element in the list.
  20085.     * @param string     $p_remove_dir   A string which contains a path to be
  20086.     *                                   removed from the memorized path of
  20087.     *                                   each element in the list, when
  20088.     *                                   relevant.
  20089.     * @return                           true on success, false on error.
  20090.     * @access public
  20091.     */
  20092.     function addModify($p_filelist, $p_add_dir, $p_remove_dir='')
  20093.     {
  20094.         $v_result = true;
  20095.  
  20096.         if (!$this->_isArchive())
  20097.             $v_result = $this->createModify($p_filelist, $p_add_dir,
  20098.                                             $p_remove_dir);
  20099.         else {
  20100.             if (is_array($p_filelist))
  20101.                 $v_list = $p_filelist;
  20102.             elseif (is_string($p_filelist))
  20103.                 $v_list = explode($this->_separator, $p_filelist);
  20104.             else {
  20105.                 $this->_error('Invalid file list');
  20106.                 return false;
  20107.             }
  20108.  
  20109.             $v_result = $this->_append($v_list, $p_add_dir, $p_remove_dir);
  20110.         }
  20111.  
  20112.         return $v_result;
  20113.     }
  20114.     // }}}
  20115.  
  20116.     // {{{ addString()
  20117.     /**
  20118.     * This method add a single string as a file at the
  20119.     * end of the existing archive. If the archive does not yet exists it
  20120.     * is created.
  20121.     *
  20122.     * @param string     $p_filename     A string which contains the full
  20123.     *                                   filename path that will be associated
  20124.     *                                   with the string.
  20125.     * @param string     $p_string       The content of the file added in
  20126.     *                                   the archive.
  20127.     * @return                           true on success, false on error.
  20128.     * @access public
  20129.     */
  20130.     function addString($p_filename, $p_string)
  20131.     {
  20132.         $v_result = true;
  20133.         
  20134.         if (!$this->_isArchive()) {
  20135.             if (!$this->_openWrite()) {
  20136.                 return false;
  20137.             }
  20138.             $this->_close();
  20139.         }
  20140.         
  20141.         if (!$this->_openAppend())
  20142.             return false;
  20143.  
  20144.         // Need to check the get back to the temporary file ? ....
  20145.         $v_result = $this->_addString($p_filename, $p_string);
  20146.  
  20147.         $this->_writeFooter();
  20148.  
  20149.         $this->_close();
  20150.  
  20151.         return $v_result;
  20152.     }
  20153.     // }}}
  20154.  
  20155.     // {{{ extractModify()
  20156.     /**
  20157.     * This method extract all the content of the archive in the directory
  20158.     * indicated by $p_path. When relevant the memorized path of the
  20159.     * files/dir can be modified by removing the $p_remove_path path at the
  20160.     * beginning of the file/dir path.
  20161.     * While extracting a file, if the directory path does not exists it is
  20162.     * created.
  20163.     * While extracting a file, if the file already exists it is replaced
  20164.     * without looking for last modification date.
  20165.     * While extracting a file, if the file already exists and is write
  20166.     * protected, the extraction is aborted.
  20167.     * While extracting a file, if a directory with the same name already
  20168.     * exists, the extraction is aborted.
  20169.     * While extracting a directory, if a file with the same name already
  20170.     * exists, the extraction is aborted.
  20171.     * While extracting a file/directory if the destination directory exist
  20172.     * and is write protected, or does not exist but can not be created,
  20173.     * the extraction is aborted.
  20174.     * If after extraction an extracted file does not show the correct
  20175.     * stored file size, the extraction is aborted.
  20176.     * When the extraction is aborted, a PEAR error text is set and false
  20177.     * is returned. However the result can be a partial extraction that may
  20178.     * need to be manually cleaned.
  20179.     *
  20180.     * @param string $p_path         The path of the directory where the
  20181.     *                               files/dir need to by extracted.
  20182.     * @param string $p_remove_path  Part of the memorized path that can be
  20183.     *                               removed if present at the beginning of
  20184.     *                               the file/dir path.
  20185.     * @return boolean               true on success, false on error.
  20186.     * @access public
  20187.     * @see extractList()
  20188.     */
  20189.     function extractModify($p_path, $p_remove_path)
  20190.     {
  20191.         $v_result = true;
  20192.         $v_list_detail = array();
  20193.  
  20194.         if ($v_result = $this->_openRead()) {
  20195.             $v_result = $this->_extractList($p_path, $v_list_detail,
  20196.                                             "complete", 0, $p_remove_path);
  20197.             $this->_close();
  20198.         }
  20199.  
  20200.         return $v_result;
  20201.     }
  20202.     // }}}
  20203.  
  20204.     // {{{ extractInString()
  20205.     /**
  20206.     * This method extract from the archive one file identified by $p_filename.
  20207.     * The return value is a string with the file content, or NULL on error.
  20208.     * @param string $p_filename     The path of the file to extract in a string.
  20209.     * @return                       a string with the file content or NULL.
  20210.     * @access public
  20211.     */
  20212.     function extractInString($p_filename)
  20213.     {
  20214.         if ($this->_openRead()) {
  20215.             $v_result = $this->_extractInString($p_filename);
  20216.             $this->_close();
  20217.         } else {
  20218.             $v_result = NULL;
  20219.         }
  20220.  
  20221.         return $v_result;
  20222.     }
  20223.     // }}}
  20224.  
  20225.     // {{{ extractList()
  20226.     /**
  20227.     * This method extract from the archive only the files indicated in the
  20228.     * $p_filelist. These files are extracted in the current directory or
  20229.     * in the directory indicated by the optional $p_path parameter.
  20230.     * If indicated the $p_remove_path can be used in the same way as it is
  20231.     * used in extractModify() method.
  20232.     * @param array  $p_filelist     An array of filenames and directory names,
  20233.     *                               or a single string with names separated
  20234.     *                               by a single blank space.
  20235.     * @param string $p_path         The path of the directory where the
  20236.     *                               files/dir need to by extracted.
  20237.     * @param string $p_remove_path  Part of the memorized path that can be
  20238.     *                               removed if present at the beginning of
  20239.     *                               the file/dir path.
  20240.     * @return                       true on success, false on error.
  20241.     * @access public
  20242.     * @see extractModify()
  20243.     */
  20244.     function extractList($p_filelist, $p_path='', $p_remove_path='')
  20245.     {
  20246.         $v_result = true;
  20247.         $v_list_detail = array();
  20248.  
  20249.         if (is_array($p_filelist))
  20250.             $v_list = $p_filelist;
  20251.         elseif (is_string($p_filelist))
  20252.             $v_list = explode($this->_separator, $p_filelist);
  20253.         else {
  20254.             $this->_error('Invalid string list');
  20255.             return false;
  20256.         }
  20257.  
  20258.         if ($v_result = $this->_openRead()) {
  20259.             $v_result = $this->_extractList($p_path, $v_list_detail, "partial",
  20260.                                             $v_list, $p_remove_path);
  20261.             $this->_close();
  20262.         }
  20263.  
  20264.         return $v_result;
  20265.     }
  20266.     // }}}
  20267.  
  20268.     // {{{ setAttribute()
  20269.     /**
  20270.     * This method set specific attributes of the archive. It uses a variable
  20271.     * list of parameters, in the format attribute code + attribute values :
  20272.     * $arch->setAttribute(ARCHIVE_TAR_ATT_SEPARATOR, ',');
  20273.     * @param mixed $argv            variable list of attributes and values
  20274.     * @return                       true on success, false on error.
  20275.     * @access public
  20276.     */
  20277.     function setAttribute()
  20278.     {
  20279.         $v_result = true;
  20280.         
  20281.         // ----- Get the number of variable list of arguments
  20282.         if (($v_size = func_num_args()) == 0) {
  20283.             return true;
  20284.         }
  20285.         
  20286.         // ----- Get the arguments
  20287.         $v_att_list = &func_get_args();
  20288.  
  20289.         // ----- Read the attributes
  20290.         $i=0;
  20291.         while ($i<$v_size) {
  20292.  
  20293.             // ----- Look for next option
  20294.             switch ($v_att_list[$i]) {
  20295.                 // ----- Look for options that request a string value
  20296.                 case ARCHIVE_TAR_ATT_SEPARATOR :
  20297.                     // ----- Check the number of parameters
  20298.                     if (($i+1) >= $v_size) {
  20299.                         $this->_error('Invalid number of parameters for '
  20300.                                       .'attribute ARCHIVE_TAR_ATT_SEPARATOR');
  20301.                         return false;
  20302.                     }
  20303.  
  20304.                     // ----- Get the value
  20305.                     $this->_separator = $v_att_list[$i+1];
  20306.                     $i++;
  20307.                 break;
  20308.  
  20309.                 default :
  20310.                     $this->_error('Unknow attribute code '.$v_att_list[$i].'');
  20311.                     return false;
  20312.             }
  20313.  
  20314.             // ----- Next attribute
  20315.             $i++;
  20316.         }
  20317.  
  20318.         return $v_result;
  20319.     }
  20320.     // }}}
  20321.  
  20322.     // {{{ _error()
  20323.     function _error($p_message)
  20324.     {
  20325.         // ----- To be completed
  20326.         $this->raiseError($p_message);
  20327.     }
  20328.     // }}}
  20329.  
  20330.     // {{{ _warning()
  20331.     function _warning($p_message)
  20332.     {
  20333.         // ----- To be completed
  20334.         $this->raiseError($p_message);
  20335.     }
  20336.     // }}}
  20337.  
  20338.     // {{{ _isArchive()
  20339.     function _isArchive($p_filename=NULL)
  20340.     {
  20341.         if ($p_filename == NULL) {
  20342.             $p_filename = $this->_tarname;
  20343.         }
  20344.         clearstatcache();
  20345.         return @is_file($p_filename);
  20346.     }
  20347.     // }}}
  20348.  
  20349.     // {{{ _openWrite()
  20350.     function _openWrite()
  20351.     {
  20352.         if ($this->_compress_type == 'gz')
  20353.             $this->_file = @gzopen($this->_tarname, "wb9");
  20354.         else if ($this->_compress_type == 'bz2')
  20355.             $this->_file = @bzopen($this->_tarname, "wb");
  20356.         else if ($this->_compress_type == 'none')
  20357.             $this->_file = @fopen($this->_tarname, "wb");
  20358.         else
  20359.             $this->_error('Unknown or missing compression type ('
  20360.                           .$this->_compress_type.')');
  20361.  
  20362.         if ($this->_file == 0) {
  20363.             $this->_error('Unable to open in write mode \''
  20364.                           .$this->_tarname.'\'');
  20365.             return false;
  20366.         }
  20367.  
  20368.         return true;
  20369.     }
  20370.     // }}}
  20371.  
  20372.     // {{{ _openRead()
  20373.     function _openRead()
  20374.     {
  20375.         if (strtolower(substr($this->_tarname, 0, 7)) == 'http://') {
  20376.  
  20377.           // ----- Look if a local copy need to be done
  20378.           if ($this->_temp_tarname == '') {
  20379.               $this->_temp_tarname = uniqid('tar').'.tmp';
  20380.               if (!$v_file_from = @fopen($this->_tarname, 'rb')) {
  20381.                 $this->_error('Unable to open in read mode \''
  20382.                               .$this->_tarname.'\'');
  20383.                 $this->_temp_tarname = '';
  20384.                 return false;
  20385.               }
  20386.               if (!$v_file_to = @fopen($this->_temp_tarname, 'wb')) {
  20387.                 $this->_error('Unable to open in write mode \''
  20388.                               .$this->_temp_tarname.'\'');
  20389.                 $this->_temp_tarname = '';
  20390.                 return false;
  20391.               }
  20392.               while ($v_data = @fread($v_file_from, 1024))
  20393.                   @fwrite($v_file_to, $v_data);
  20394.               @fclose($v_file_from);
  20395.               @fclose($v_file_to);
  20396.           }
  20397.  
  20398.           // ----- File to open if the local copy
  20399.           $v_filename = $this->_temp_tarname;
  20400.  
  20401.         } else
  20402.           // ----- File to open if the normal Tar file
  20403.           $v_filename = $this->_tarname;
  20404.  
  20405.         if ($this->_compress_type == 'gz')
  20406.             $this->_file = @gzopen($v_filename, "rb");
  20407.         else if ($this->_compress_type == 'bz2')
  20408.             $this->_file = @bzopen($v_filename, "rb");
  20409.         else if ($this->_compress_type == 'none')
  20410.             $this->_file = @fopen($v_filename, "rb");
  20411.         else
  20412.             $this->_error('Unknown or missing compression type ('
  20413.                           .$this->_compress_type.')');
  20414.  
  20415.         if ($this->_file == 0) {
  20416.             $this->_error('Unable to open in read mode \''.$v_filename.'\'');
  20417.             return false;
  20418.         }
  20419.  
  20420.         return true;
  20421.     }
  20422.     // }}}
  20423.  
  20424.     // {{{ _openReadWrite()
  20425.     function _openReadWrite()
  20426.     {
  20427.         if ($this->_compress_type == 'gz')
  20428.             $this->_file = @gzopen($this->_tarname, "r+b");
  20429.         else if ($this->_compress_type == 'bz2')
  20430.             $this->_file = @bzopen($this->_tarname, "r+b");
  20431.         else if ($this->_compress_type == 'none')
  20432.             $this->_file = @fopen($this->_tarname, "r+b");
  20433.         else
  20434.             $this->_error('Unknown or missing compression type ('
  20435.                           .$this->_compress_type.')');
  20436.  
  20437.         if ($this->_file == 0) {
  20438.             $this->_error('Unable to open in read/write mode \''
  20439.                           .$this->_tarname.'\'');
  20440.             return false;
  20441.         }
  20442.  
  20443.         return true;
  20444.     }
  20445.     // }}}
  20446.  
  20447.     // {{{ _close()
  20448.     function _close()
  20449.     {
  20450.         //if (isset($this->_file)) {
  20451.         if (is_resource($this->_file)) {
  20452.             if ($this->_compress_type == 'gz')
  20453.                 @gzclose($this->_file);
  20454.             else if ($this->_compress_type == 'bz2')
  20455.                 @bzclose($this->_file);
  20456.             else if ($this->_compress_type == 'none')
  20457.                 @fclose($this->_file);
  20458.             else
  20459.                 $this->_error('Unknown or missing compression type ('
  20460.                               .$this->_compress_type.')');
  20461.  
  20462.             $this->_file = 0;
  20463.         }
  20464.  
  20465.         // ----- Look if a local copy need to be erase
  20466.         // Note that it might be interesting to keep the url for a time : ToDo
  20467.         if ($this->_temp_tarname != '') {
  20468.             @unlink($this->_temp_tarname);
  20469.             $this->_temp_tarname = '';
  20470.         }
  20471.  
  20472.         return true;
  20473.     }
  20474.     // }}}
  20475.  
  20476.     // {{{ _cleanFile()
  20477.     function _cleanFile()
  20478.     {
  20479.         $this->_close();
  20480.  
  20481.         // ----- Look for a local copy
  20482.         if ($this->_temp_tarname != '') {
  20483.             // ----- Remove the local copy but not the remote tarname
  20484.             @unlink($this->_temp_tarname);
  20485.             $this->_temp_tarname = '';
  20486.         } else {
  20487.             // ----- Remove the local tarname file
  20488.             @unlink($this->_tarname);
  20489.         }
  20490.         $this->_tarname = '';
  20491.  
  20492.         return true;
  20493.     }
  20494.     // }}}
  20495.  
  20496.     // {{{ _writeBlock()
  20497.     function _writeBlock($p_binary_data, $p_len=null)
  20498.     {
  20499.       if (is_resource($this->_file)) {
  20500.           if ($p_len === null) {
  20501.               if ($this->_compress_type == 'gz')
  20502.                   @gzputs($this->_file, $p_binary_data);
  20503.               else if ($this->_compress_type == 'bz2')
  20504.                   @bzwrite($this->_file, $p_binary_data);
  20505.               else if ($this->_compress_type == 'none')
  20506.                   @fputs($this->_file, $p_binary_data);
  20507.               else
  20508.                   $this->_error('Unknown or missing compression type ('
  20509.                                 .$this->_compress_type.')');
  20510.           } else {
  20511.               if ($this->_compress_type == 'gz')
  20512.                   @gzputs($this->_file, $p_binary_data, $p_len);
  20513.               else if ($this->_compress_type == 'bz2')
  20514.                   @bzwrite($this->_file, $p_binary_data, $p_len);
  20515.               else if ($this->_compress_type == 'none')
  20516.                   @fputs($this->_file, $p_binary_data, $p_len);
  20517.               else
  20518.                   $this->_error('Unknown or missing compression type ('
  20519.                                 .$this->_compress_type.')');
  20520.  
  20521.           }
  20522.       }
  20523.       return true;
  20524.     }
  20525.     // }}}
  20526.  
  20527.     // {{{ _readBlock()
  20528.     function _readBlock()
  20529.     {
  20530.       $v_block = null;
  20531.       if (is_resource($this->_file)) {
  20532.           if ($this->_compress_type == 'gz')
  20533.               $v_block = @gzread($this->_file, 512);
  20534.           else if ($this->_compress_type == 'bz2')
  20535.               $v_block = @bzread($this->_file, 512);
  20536.           else if ($this->_compress_type == 'none')
  20537.               $v_block = @fread($this->_file, 512);
  20538.           else
  20539.               $this->_error('Unknown or missing compression type ('
  20540.                             .$this->_compress_type.')');
  20541.       }
  20542.       return $v_block;
  20543.     }
  20544.     // }}}
  20545.  
  20546.     // {{{ _jumpBlock()
  20547.     function _jumpBlock($p_len=null)
  20548.     {
  20549.       if (is_resource($this->_file)) {
  20550.           if ($p_len === null)
  20551.               $p_len = 1;
  20552.  
  20553.           if ($this->_compress_type == 'gz') {
  20554.               @gzseek($this->_file, gztell($this->_file)+($p_len*512));
  20555.           }
  20556.           else if ($this->_compress_type == 'bz2') {
  20557.               // ----- Replace missing bztell() and bzseek()
  20558.               for ($i=0; $i<$p_len; $i++)
  20559.                   $this->_readBlock();
  20560.           } else if ($this->_compress_type == 'none')
  20561.               @fseek($this->_file, ftell($this->_file)+($p_len*512));
  20562.           else
  20563.               $this->_error('Unknown or missing compression type ('
  20564.                             .$this->_compress_type.')');
  20565.  
  20566.       }
  20567.       return true;
  20568.     }
  20569.     // }}}
  20570.  
  20571.     // {{{ _writeFooter()
  20572.     function _writeFooter()
  20573.     {
  20574.       if (is_resource($this->_file)) {
  20575.           // ----- Write the last 0 filled block for end of archive
  20576.           $v_binary_data = pack('a1024', '');
  20577.           $this->_writeBlock($v_binary_data);
  20578.       }
  20579.       return true;
  20580.     }
  20581.     // }}}
  20582.  
  20583.     // {{{ _addList()
  20584.     function _addList($p_list, $p_add_dir, $p_remove_dir)
  20585.     {
  20586.       $v_result=true;
  20587.       $v_header = array();
  20588.  
  20589.       // ----- Remove potential windows directory separator
  20590.       $p_add_dir = $this->_translateWinPath($p_add_dir);
  20591.       $p_remove_dir = $this->_translateWinPath($p_remove_dir, false);
  20592.  
  20593.       if (!$this->_file) {
  20594.           $this->_error('Invalid file descriptor');
  20595.           return false;
  20596.       }
  20597.  
  20598.       if (sizeof($p_list) == 0)
  20599.           return true;
  20600.  
  20601.       foreach ($p_list as $v_filename) {
  20602.           if (!$v_result) {
  20603.               break;
  20604.           }
  20605.  
  20606.         // ----- Skip the current tar name
  20607.         if ($v_filename == $this->_tarname)
  20608.             continue;
  20609.  
  20610.         if ($v_filename == '')
  20611.             continue;
  20612.  
  20613.         if (!file_exists($v_filename)) {
  20614.             $this->_warning("File '$v_filename' does not exist");
  20615.             continue;
  20616.         }
  20617.  
  20618.         // ----- Add the file or directory header
  20619.         if (!$this->_addFile($v_filename, $v_header, $p_add_dir, $p_remove_dir))
  20620.             return false;
  20621.  
  20622.         if (@is_dir($v_filename)) {
  20623.             if (!($p_hdir = opendir($v_filename))) {
  20624.                 $this->_warning("Directory '$v_filename' can not be read");
  20625.                 continue;
  20626.             }
  20627.             while (false !== ($p_hitem = readdir($p_hdir))) {
  20628.                 if (($p_hitem != '.') && ($p_hitem != '..')) {
  20629.                     if ($v_filename != ".")
  20630.                         $p_temp_list[0] = $v_filename.'/'.$p_hitem;
  20631.                     else
  20632.                         $p_temp_list[0] = $p_hitem;
  20633.  
  20634.                     $v_result = $this->_addList($p_temp_list,
  20635.                                                 $p_add_dir,
  20636.                                                 $p_remove_dir);
  20637.                 }
  20638.             }
  20639.  
  20640.             unset($p_temp_list);
  20641.             unset($p_hdir);
  20642.             unset($p_hitem);
  20643.         }
  20644.       }
  20645.  
  20646.       return $v_result;
  20647.     }
  20648.     // }}}
  20649.  
  20650.     // {{{ _addFile()
  20651.     function _addFile($p_filename, &$p_header, $p_add_dir, $p_remove_dir)
  20652.     {
  20653.       if (!$this->_file) {
  20654.           $this->_error('Invalid file descriptor');
  20655.           return false;
  20656.       }
  20657.  
  20658.       if ($p_filename == '') {
  20659.           $this->_error('Invalid file name');
  20660.           return false;
  20661.       }
  20662.  
  20663.       // ----- Calculate the stored filename
  20664.       $p_filename = $this->_translateWinPath($p_filename, false);;
  20665.       $v_stored_filename = $p_filename;
  20666.       if (strcmp($p_filename, $p_remove_dir) == 0) {
  20667.           return true;
  20668.       }
  20669.       if ($p_remove_dir != '') {
  20670.           if (substr($p_remove_dir, -1) != '/')
  20671.               $p_remove_dir .= '/';
  20672.  
  20673.           if (substr($p_filename, 0, strlen($p_remove_dir)) == $p_remove_dir)
  20674.               $v_stored_filename = substr($p_filename, strlen($p_remove_dir));
  20675.       }
  20676.       $v_stored_filename = $this->_translateWinPath($v_stored_filename);
  20677.       if ($p_add_dir != '') {
  20678.           if (substr($p_add_dir, -1) == '/')
  20679.               $v_stored_filename = $p_add_dir.$v_stored_filename;
  20680.           else
  20681.               $v_stored_filename = $p_add_dir.'/'.$v_stored_filename;
  20682.       }
  20683.  
  20684.       $v_stored_filename = $this->_pathReduction($v_stored_filename);
  20685.  
  20686.       if ($this->_isArchive($p_filename)) {
  20687.           if (($v_file = @fopen($p_filename, "rb")) == 0) {
  20688.               $this->_warning("Unable to open file '".$p_filename
  20689.                               ."' in binary read mode");
  20690.               return true;
  20691.           }
  20692.  
  20693.           if (!$this->_writeHeader($p_filename, $v_stored_filename))
  20694.               return false;
  20695.  
  20696.           while (($v_buffer = fread($v_file, 512)) != '') {
  20697.               $v_binary_data = pack("a512", "$v_buffer");
  20698.               $this->_writeBlock($v_binary_data);
  20699.           }
  20700.  
  20701.           fclose($v_file);
  20702.  
  20703.       } else {
  20704.           // ----- Only header for dir
  20705.           if (!$this->_writeHeader($p_filename, $v_stored_filename))
  20706.               return false;
  20707.       }
  20708.  
  20709.       return true;
  20710.     }
  20711.     // }}}
  20712.  
  20713.     // {{{ _addString()
  20714.     function _addString($p_filename, $p_string)
  20715.     {
  20716.       if (!$this->_file) {
  20717.           $this->_error('Invalid file descriptor');
  20718.           return false;
  20719.       }
  20720.  
  20721.       if ($p_filename == '') {
  20722.           $this->_error('Invalid file name');
  20723.           return false;
  20724.       }
  20725.  
  20726.       // ----- Calculate the stored filename
  20727.       $p_filename = $this->_translateWinPath($p_filename, false);;
  20728.  
  20729.       if (!$this->_writeHeaderBlock($p_filename, strlen($p_string),
  20730.                                       time(), 384, "", 0, 0))
  20731.           return false;
  20732.  
  20733.       $i=0;
  20734.       while (($v_buffer = substr($p_string, (($i++)*512), 512)) != '') {
  20735.           $v_binary_data = pack("a512", $v_buffer);
  20736.           $this->_writeBlock($v_binary_data);
  20737.       }
  20738.  
  20739.       return true;
  20740.     }
  20741.     // }}}
  20742.  
  20743.     // {{{ _writeHeader()
  20744.     function _writeHeader($p_filename, $p_stored_filename)
  20745.     {
  20746.         if ($p_stored_filename == '')
  20747.             $p_stored_filename = $p_filename;
  20748.         $v_reduce_filename = $this->_pathReduction($p_stored_filename);
  20749.  
  20750.         if (strlen($v_reduce_filename) > 99) {
  20751.           if (!$this->_writeLongHeader($v_reduce_filename))
  20752.             return false;
  20753.         }
  20754.  
  20755.         $v_info = stat($p_filename);
  20756.         $v_uid = sprintf("%6s ", DecOct($v_info[4]));
  20757.         $v_gid = sprintf("%6s ", DecOct($v_info[5]));
  20758.         $v_perms = sprintf("%6s ", DecOct(fileperms($p_filename)));
  20759.  
  20760.         $v_mtime = sprintf("%11s", DecOct(filemtime($p_filename)));
  20761.  
  20762.         if (@is_dir($p_filename)) {
  20763.           $v_typeflag = "5";
  20764.           $v_size = sprintf("%11s ", DecOct(0));
  20765.         } else {
  20766.           $v_typeflag = '';
  20767.           clearstatcache();
  20768.           $v_size = sprintf("%11s ", DecOct(filesize($p_filename)));
  20769.         }
  20770.  
  20771.         $v_linkname = '';
  20772.  
  20773.         $v_magic = '';
  20774.  
  20775.         $v_version = '';
  20776.  
  20777.         $v_uname = '';
  20778.  
  20779.         $v_gname = '';
  20780.  
  20781.         $v_devmajor = '';
  20782.  
  20783.         $v_devminor = '';
  20784.  
  20785.         $v_prefix = '';
  20786.  
  20787.         $v_binary_data_first = pack("a100a8a8a8a12A12",
  20788.                                     $v_reduce_filename, $v_perms, $v_uid,
  20789.                                     $v_gid, $v_size, $v_mtime);
  20790.         $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12",
  20791.                                    $v_typeflag, $v_linkname, $v_magic,
  20792.                                    $v_version, $v_uname, $v_gname,
  20793.                                    $v_devmajor, $v_devminor, $v_prefix, '');
  20794.  
  20795.         // ----- Calculate the checksum
  20796.         $v_checksum = 0;
  20797.         // ..... First part of the header
  20798.         for ($i=0; $i<148; $i++)
  20799.             $v_checksum += ord(substr($v_binary_data_first,$i,1));
  20800.         // ..... Ignore the checksum value and replace it by ' ' (space)
  20801.         for ($i=148; $i<156; $i++)
  20802.             $v_checksum += ord(' ');
  20803.         // ..... Last part of the header
  20804.         for ($i=156, $j=0; $i<512; $i++, $j++)
  20805.             $v_checksum += ord(substr($v_binary_data_last,$j,1));
  20806.  
  20807.         // ----- Write the first 148 bytes of the header in the archive
  20808.         $this->_writeBlock($v_binary_data_first, 148);
  20809.  
  20810.         // ----- Write the calculated checksum
  20811.         $v_checksum = sprintf("%6s ", DecOct($v_checksum));
  20812.         $v_binary_data = pack("a8", $v_checksum);
  20813.         $this->_writeBlock($v_binary_data, 8);
  20814.  
  20815.         // ----- Write the last 356 bytes of the header in the archive
  20816.         $this->_writeBlock($v_binary_data_last, 356);
  20817.  
  20818.         return true;
  20819.     }
  20820.     // }}}
  20821.  
  20822.     // {{{ _writeHeaderBlock()
  20823.     function _writeHeaderBlock($p_filename, $p_size, $p_mtime=0, $p_perms=0,
  20824.                                $p_type='', $p_uid=0, $p_gid=0)
  20825.     {
  20826.         $p_filename = $this->_pathReduction($p_filename);
  20827.  
  20828.         if (strlen($p_filename) > 99) {
  20829.           if (!$this->_writeLongHeader($p_filename))
  20830.             return false;
  20831.         }
  20832.  
  20833.         if ($p_type == "5") {
  20834.           $v_size = sprintf("%11s ", DecOct(0));
  20835.         } else {
  20836.           $v_size = sprintf("%11s ", DecOct($p_size));
  20837.         }
  20838.  
  20839.         $v_uid = sprintf("%6s ", DecOct($p_uid));
  20840.         $v_gid = sprintf("%6s ", DecOct($p_gid));
  20841.         $v_perms = sprintf("%6s ", DecOct($p_perms));
  20842.  
  20843.         $v_mtime = sprintf("%11s", DecOct($p_mtime));
  20844.  
  20845.         $v_linkname = '';
  20846.  
  20847.         $v_magic = '';
  20848.  
  20849.         $v_version = '';
  20850.  
  20851.         $v_uname = '';
  20852.  
  20853.         $v_gname = '';
  20854.  
  20855.         $v_devmajor = '';
  20856.  
  20857.         $v_devminor = '';
  20858.  
  20859.         $v_prefix = '';
  20860.  
  20861.         $v_binary_data_first = pack("a100a8a8a8a12A12",
  20862.                                     $p_filename, $v_perms, $v_uid, $v_gid,
  20863.                                     $v_size, $v_mtime);
  20864.         $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12",
  20865.                                    $p_type, $v_linkname, $v_magic,
  20866.                                    $v_version, $v_uname, $v_gname,
  20867.                                    $v_devmajor, $v_devminor, $v_prefix, '');
  20868.  
  20869.         // ----- Calculate the checksum
  20870.         $v_checksum = 0;
  20871.         // ..... First part of the header
  20872.         for ($i=0; $i<148; $i++)
  20873.             $v_checksum += ord(substr($v_binary_data_first,$i,1));
  20874.         // ..... Ignore the checksum value and replace it by ' ' (space)
  20875.         for ($i=148; $i<156; $i++)
  20876.             $v_checksum += ord(' ');
  20877.         // ..... Last part of the header
  20878.         for ($i=156, $j=0; $i<512; $i++, $j++)
  20879.             $v_checksum += ord(substr($v_binary_data_last,$j,1));
  20880.  
  20881.         // ----- Write the first 148 bytes of the header in the archive
  20882.         $this->_writeBlock($v_binary_data_first, 148);
  20883.  
  20884.         // ----- Write the calculated checksum
  20885.         $v_checksum = sprintf("%6s ", DecOct($v_checksum));
  20886.         $v_binary_data = pack("a8", $v_checksum);
  20887.         $this->_writeBlock($v_binary_data, 8);
  20888.  
  20889.         // ----- Write the last 356 bytes of the header in the archive
  20890.         $this->_writeBlock($v_binary_data_last, 356);
  20891.  
  20892.         return true;
  20893.     }
  20894.     // }}}
  20895.  
  20896.     // {{{ _writeLongHeader()
  20897.     function _writeLongHeader($p_filename)
  20898.     {
  20899.         $v_size = sprintf("%11s ", DecOct(strlen($p_filename)));
  20900.  
  20901.         $v_typeflag = 'L';
  20902.  
  20903.         $v_linkname = '';
  20904.  
  20905.         $v_magic = '';
  20906.  
  20907.         $v_version = '';
  20908.  
  20909.         $v_uname = '';
  20910.  
  20911.         $v_gname = '';
  20912.  
  20913.         $v_devmajor = '';
  20914.  
  20915.         $v_devminor = '';
  20916.  
  20917.         $v_prefix = '';
  20918.  
  20919.         $v_binary_data_first = pack("a100a8a8a8a12A12",
  20920.                                     '././@LongLink', 0, 0, 0, $v_size, 0);
  20921.         $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12",
  20922.                                    $v_typeflag, $v_linkname, $v_magic,
  20923.                                    $v_version, $v_uname, $v_gname,
  20924.                                    $v_devmajor, $v_devminor, $v_prefix, '');
  20925.  
  20926.         // ----- Calculate the checksum
  20927.         $v_checksum = 0;
  20928.         // ..... First part of the header
  20929.         for ($i=0; $i<148; $i++)
  20930.             $v_checksum += ord(substr($v_binary_data_first,$i,1));
  20931.         // ..... Ignore the checksum value and replace it by ' ' (space)
  20932.         for ($i=148; $i<156; $i++)
  20933.             $v_checksum += ord(' ');
  20934.         // ..... Last part of the header
  20935.         for ($i=156, $j=0; $i<512; $i++, $j++)
  20936.             $v_checksum += ord(substr($v_binary_data_last,$j,1));
  20937.  
  20938.         // ----- Write the first 148 bytes of the header in the archive
  20939.         $this->_writeBlock($v_binary_data_first, 148);
  20940.  
  20941.         // ----- Write the calculated checksum
  20942.         $v_checksum = sprintf("%6s ", DecOct($v_checksum));
  20943.         $v_binary_data = pack("a8", $v_checksum);
  20944.         $this->_writeBlock($v_binary_data, 8);
  20945.  
  20946.         // ----- Write the last 356 bytes of the header in the archive
  20947.         $this->_writeBlock($v_binary_data_last, 356);
  20948.  
  20949.         // ----- Write the filename as content of the block
  20950.         $i=0;
  20951.         while (($v_buffer = substr($p_filename, (($i++)*512), 512)) != '') {
  20952.             $v_binary_data = pack("a512", "$v_buffer");
  20953.             $this->_writeBlock($v_binary_data);
  20954.         }
  20955.  
  20956.         return true;
  20957.     }
  20958.     // }}}
  20959.  
  20960.     // {{{ _readHeader()
  20961.     function _readHeader($v_binary_data, &$v_header)
  20962.     {
  20963.         if (strlen($v_binary_data)==0) {
  20964.             $v_header['filename'] = '';
  20965.             return true;
  20966.         }
  20967.  
  20968.         if (strlen($v_binary_data) != 512) {
  20969.             $v_header['filename'] = '';
  20970.             $this->_error('Invalid block size : '.strlen($v_binary_data));
  20971.             return false;
  20972.         }
  20973.  
  20974.         if (!is_array($v_header)) {
  20975.             $v_header = array();
  20976.         }
  20977.         // ----- Calculate the checksum
  20978.         $v_checksum = 0;
  20979.         // ..... First part of the header
  20980.         for ($i=0; $i<148; $i++)
  20981.             $v_checksum+=ord(substr($v_binary_data,$i,1));
  20982.         // ..... Ignore the checksum value and replace it by ' ' (space)
  20983.         for ($i=148; $i<156; $i++)
  20984.             $v_checksum += ord(' ');
  20985.         // ..... Last part of the header
  20986.         for ($i=156; $i<512; $i++)
  20987.            $v_checksum+=ord(substr($v_binary_data,$i,1));
  20988.  
  20989.         $v_data = unpack("a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/"
  20990.                          ."a8checksum/a1typeflag/a100link/a6magic/a2version/"
  20991.                          ."a32uname/a32gname/a8devmajor/a8devminor",
  20992.                          $v_binary_data);
  20993.  
  20994.         // ----- Extract the checksum
  20995.         $v_header['checksum'] = OctDec(trim($v_data['checksum']));
  20996.         if ($v_header['checksum'] != $v_checksum) {
  20997.             $v_header['filename'] = '';
  20998.  
  20999.             // ----- Look for last block (empty block)
  21000.             if (($v_checksum == 256) && ($v_header['checksum'] == 0))
  21001.                 return true;
  21002.  
  21003.             $this->_error('Invalid checksum for file "'.$v_data['filename']
  21004.                           .'" : '.$v_checksum.' calculated, '
  21005.                           .$v_header['checksum'].' expected');
  21006.             return false;
  21007.         }
  21008.  
  21009.         // ----- Extract the properties
  21010.         $v_header['filename'] = trim($v_data['filename']);
  21011.         if ($this->_maliciousFilename($v_header['filename'])) {
  21012.             $this->_error('Malicious .tar detected, file "' . $v_header['filename'] .
  21013.                 '" will not install in desired directory tree');
  21014.             return false;
  21015.         }
  21016.         $v_header['mode'] = OctDec(trim($v_data['mode']));
  21017.         $v_header['uid'] = OctDec(trim($v_data['uid']));
  21018.         $v_header['gid'] = OctDec(trim($v_data['gid']));
  21019.         $v_header['size'] = OctDec(trim($v_data['size']));
  21020.         $v_header['mtime'] = OctDec(trim($v_data['mtime']));
  21021.         if (($v_header['typeflag'] = $v_data['typeflag']) == "5") {
  21022.           $v_header['size'] = 0;
  21023.         }
  21024.         $v_header['link'] = trim($v_data['link']);
  21025.         /* ----- All these fields are removed form the header because
  21026.         they do not carry interesting info
  21027.         $v_header[magic] = trim($v_data[magic]);
  21028.         $v_header[version] = trim($v_data[version]);
  21029.         $v_header[uname] = trim($v_data[uname]);
  21030.         $v_header[gname] = trim($v_data[gname]);
  21031.         $v_header[devmajor] = trim($v_data[devmajor]);
  21032.         $v_header[devminor] = trim($v_data[devminor]);
  21033.         */
  21034.  
  21035.         return true;
  21036.     }
  21037.     // }}}
  21038.  
  21039.     // {{{ _maliciousFilename()
  21040.     /**
  21041.      * Detect and report a malicious file name
  21042.      *
  21043.      * @param string $file
  21044.      * @return bool
  21045.      * @access private
  21046.      */
  21047.     function _maliciousFilename($file)
  21048.     {
  21049.         if (strpos($file, '/../') !== false) {
  21050.             return true;
  21051.         }
  21052.         if (strpos($file, '../') === 0) {
  21053.             return true;
  21054.         }
  21055.         return false;
  21056.     }
  21057.     // }}}
  21058.  
  21059.     // {{{ _readLongHeader()
  21060.     function _readLongHeader(&$v_header)
  21061.     {
  21062.       $v_filename = '';
  21063.       $n = floor($v_header['size']/512);
  21064.       for ($i=0; $i<$n; $i++) {
  21065.         $v_content = $this->_readBlock();
  21066.         $v_filename .= $v_content;
  21067.       }
  21068.       if (($v_header['size'] % 512) != 0) {
  21069.         $v_content = $this->_readBlock();
  21070.         $v_filename .= $v_content;
  21071.       }
  21072.  
  21073.       // ----- Read the next header
  21074.       $v_binary_data = $this->_readBlock();
  21075.  
  21076.       if (!$this->_readHeader($v_binary_data, $v_header))
  21077.         return false;
  21078.  
  21079.       $v_header['filename'] = $v_filename;
  21080.         if ($this->_maliciousFilename($v_filename)) {
  21081.             $this->_error('Malicious .tar detected, file "' . $v_filename .
  21082.                 '" will not install in desired directory tree');
  21083.             return false;
  21084.       }
  21085.  
  21086.       return true;
  21087.     }
  21088.     // }}}
  21089.  
  21090.     // {{{ _extractInString()
  21091.     /**
  21092.     * This method extract from the archive one file identified by $p_filename.
  21093.     * The return value is a string with the file content, or NULL on error.
  21094.     * @param string $p_filename     The path of the file to extract in a string.
  21095.     * @return                       a string with the file content or NULL.
  21096.     * @access private
  21097.     */
  21098.     function _extractInString($p_filename)
  21099.     {
  21100.         $v_result_str = "";
  21101.  
  21102.         While (strlen($v_binary_data = $this->_readBlock()) != 0)
  21103.         {
  21104.           if (!$this->_readHeader($v_binary_data, $v_header))
  21105.             return NULL;
  21106.  
  21107.           if ($v_header['filename'] == '')
  21108.             continue;
  21109.  
  21110.           // ----- Look for long filename
  21111.           if ($v_header['typeflag'] == 'L') {
  21112.             if (!$this->_readLongHeader($v_header))
  21113.               return NULL;
  21114.           }
  21115.  
  21116.           if ($v_header['filename'] == $p_filename) {
  21117.               if ($v_header['typeflag'] == "5") {
  21118.                   $this->_error('Unable to extract in string a directory '
  21119.                                 .'entry {'.$v_header['filename'].'}');
  21120.                   return NULL;
  21121.               } else {
  21122.                   $n = floor($v_header['size']/512);
  21123.                   for ($i=0; $i<$n; $i++) {
  21124.                       $v_result_str .= $this->_readBlock();
  21125.                   }
  21126.                   if (($v_header['size'] % 512) != 0) {
  21127.                       $v_content = $this->_readBlock();
  21128.                       $v_result_str .= substr($v_content, 0,
  21129.                                               ($v_header['size'] % 512));
  21130.                   }
  21131.                   return $v_result_str;
  21132.               }
  21133.           } else {
  21134.               $this->_jumpBlock(ceil(($v_header['size']/512)));
  21135.           }
  21136.         }
  21137.  
  21138.         return NULL;
  21139.     }
  21140.     // }}}
  21141.  
  21142.     // {{{ _extractList()
  21143.     function _extractList($p_path, &$p_list_detail, $p_mode,
  21144.                           $p_file_list, $p_remove_path)
  21145.     {
  21146.     $v_result=true;
  21147.     $v_nb = 0;
  21148.     $v_extract_all = true;
  21149.     $v_listing = false;
  21150.  
  21151.     $p_path = $this->_translateWinPath($p_path, false);
  21152.     if ($p_path == '' || (substr($p_path, 0, 1) != '/'
  21153.         && substr($p_path, 0, 3) != "../" && !strpos($p_path, ':'))) {
  21154.       $p_path = "./".$p_path;
  21155.     }
  21156.     $p_remove_path = $this->_translateWinPath($p_remove_path);
  21157.  
  21158.     // ----- Look for path to remove format (should end by /)
  21159.     if (($p_remove_path != '') && (substr($p_remove_path, -1) != '/'))
  21160.       $p_remove_path .= '/';
  21161.     $p_remove_path_size = strlen($p_remove_path);
  21162.  
  21163.     switch ($p_mode) {
  21164.       case "complete" :
  21165.         $v_extract_all = TRUE;
  21166.         $v_listing = FALSE;
  21167.       break;
  21168.       case "partial" :
  21169.           $v_extract_all = FALSE;
  21170.           $v_listing = FALSE;
  21171.       break;
  21172.       case "list" :
  21173.           $v_extract_all = FALSE;
  21174.           $v_listing = TRUE;
  21175.       break;
  21176.       default :
  21177.         $this->_error('Invalid extract mode ('.$p_mode.')');
  21178.         return false;
  21179.     }
  21180.  
  21181.     clearstatcache();
  21182.  
  21183.     while (strlen($v_binary_data = $this->_readBlock()) != 0)
  21184.     {
  21185.       $v_extract_file = FALSE;
  21186.       $v_extraction_stopped = 0;
  21187.  
  21188.       if (!$this->_readHeader($v_binary_data, $v_header))
  21189.         return false;
  21190.  
  21191.       if ($v_header['filename'] == '') {
  21192.         continue;
  21193.       }
  21194.  
  21195.       // ----- Look for long filename
  21196.       if ($v_header['typeflag'] == 'L') {
  21197.         if (!$this->_readLongHeader($v_header))
  21198.           return false;
  21199.       }
  21200.  
  21201.       if ((!$v_extract_all) && (is_array($p_file_list))) {
  21202.         // ----- By default no unzip if the file is not found
  21203.         $v_extract_file = false;
  21204.  
  21205.         for ($i=0; $i<sizeof($p_file_list); $i++) {
  21206.           // ----- Look if it is a directory
  21207.           if (substr($p_file_list[$i], -1) == '/') {
  21208.             // ----- Look if the directory is in the filename path
  21209.             if ((strlen($v_header['filename']) > strlen($p_file_list[$i]))
  21210.                 && (substr($v_header['filename'], 0, strlen($p_file_list[$i]))
  21211.                     == $p_file_list[$i])) {
  21212.               $v_extract_file = TRUE;
  21213.               break;
  21214.             }
  21215.           }
  21216.  
  21217.           // ----- It is a file, so compare the file names
  21218.           elseif ($p_file_list[$i] == $v_header['filename']) {
  21219.             $v_extract_file = TRUE;
  21220.             break;
  21221.           }
  21222.         }
  21223.       } else {
  21224.         $v_extract_file = TRUE;
  21225.       }
  21226.  
  21227.       // ----- Look if this file need to be extracted
  21228.       if (($v_extract_file) && (!$v_listing))
  21229.       {
  21230.         if (($p_remove_path != '')
  21231.             && (substr($v_header['filename'], 0, $p_remove_path_size)
  21232.                 == $p_remove_path))
  21233.           $v_header['filename'] = substr($v_header['filename'],
  21234.                                          $p_remove_path_size);
  21235.         if (($p_path != './') && ($p_path != '/')) {
  21236.           while (substr($p_path, -1) == '/')
  21237.             $p_path = substr($p_path, 0, strlen($p_path)-1);
  21238.  
  21239.           if (substr($v_header['filename'], 0, 1) == '/')
  21240.               $v_header['filename'] = $p_path.$v_header['filename'];
  21241.           else
  21242.             $v_header['filename'] = $p_path.'/'.$v_header['filename'];
  21243.         }
  21244.         if (file_exists($v_header['filename'])) {
  21245.           if (   (@is_dir($v_header['filename']))
  21246.               && ($v_header['typeflag'] == '')) {
  21247.             $this->_error('File '.$v_header['filename']
  21248.                           .' already exists as a directory');
  21249.             return false;
  21250.           }
  21251.           if (   ($this->_isArchive($v_header['filename']))
  21252.               && ($v_header['typeflag'] == "5")) {
  21253.             $this->_error('Directory '.$v_header['filename']
  21254.                           .' already exists as a file');
  21255.             return false;
  21256.           }
  21257.           if (!is_writeable($v_header['filename'])) {
  21258.             $this->_error('File '.$v_header['filename']
  21259.                           .' already exists and is write protected');
  21260.             return false;
  21261.           }
  21262.           if (filemtime($v_header['filename']) > $v_header['mtime']) {
  21263.             // To be completed : An error or silent no replace ?
  21264.           }
  21265.         }
  21266.  
  21267.         // ----- Check the directory availability and create it if necessary
  21268.         elseif (($v_result
  21269.                  = $this->_dirCheck(($v_header['typeflag'] == "5"
  21270.                                     ?$v_header['filename']
  21271.                                     :dirname($v_header['filename'])))) != 1) {
  21272.             $this->_error('Unable to create path for '.$v_header['filename']);
  21273.             return false;
  21274.         }
  21275.  
  21276.         if ($v_extract_file) {
  21277.           if ($v_header['typeflag'] == "5") {
  21278.             if (!@file_exists($v_header['filename'])) {
  21279.                 if (!@mkdir($v_header['filename'], 0777)) {
  21280.                     $this->_error('Unable to create directory {'
  21281.                                   .$v_header['filename'].'}');
  21282.                     return false;
  21283.                 }
  21284.             }
  21285.           } elseif ($v_header['typeflag'] == "2") {
  21286.               if (!@symlink($v_header['link'], $v_header['filename'])) {
  21287.                   $this->_error('Unable to extract symbolic link {'
  21288.                                 .$v_header['filename'].'}');
  21289.                   return false;
  21290.               }
  21291.           } else {
  21292.               if (($v_dest_file = @fopen($v_header['filename'], "wb")) == 0) {
  21293.                   $this->_error('Error while opening {'.$v_header['filename']
  21294.                                 .'} in write binary mode');
  21295.                   return false;
  21296.               } else {
  21297.                   $n = floor($v_header['size']/512);
  21298.                   for ($i=0; $i<$n; $i++) {
  21299.                       $v_content = $this->_readBlock();
  21300.                       fwrite($v_dest_file, $v_content, 512);
  21301.                   }
  21302.             if (($v_header['size'] % 512) != 0) {
  21303.               $v_content = $this->_readBlock();
  21304.               fwrite($v_dest_file, $v_content, ($v_header['size'] % 512));
  21305.             }
  21306.  
  21307.             @fclose($v_dest_file);
  21308.  
  21309.             // ----- Change the file mode, mtime
  21310.             @touch($v_header['filename'], $v_header['mtime']);
  21311.             if ($v_header['mode'] & 0111) {
  21312.                 // make file executable, obey umask
  21313.                 $mode = fileperms($v_header['filename']) | (~umask() & 0111);
  21314.                 @chmod($v_header['filename'], $mode);
  21315.             }
  21316.           }
  21317.  
  21318.           // ----- Check the file size
  21319.           clearstatcache();
  21320.           if (filesize($v_header['filename']) != $v_header['size']) {
  21321.               $this->_error('Extracted file '.$v_header['filename']
  21322.                             .' does not have the correct file size \''
  21323.                             .filesize($v_header['filename'])
  21324.                             .'\' ('.$v_header['size']
  21325.                             .' expected). Archive may be corrupted.');
  21326.               return false;
  21327.           }
  21328.           }
  21329.         } else {
  21330.           $this->_jumpBlock(ceil(($v_header['size']/512)));
  21331.         }
  21332.       } else {
  21333.           $this->_jumpBlock(ceil(($v_header['size']/512)));
  21334.       }
  21335.  
  21336.       /* TBC : Seems to be unused ...
  21337.       if ($this->_compress)
  21338.         $v_end_of_file = @gzeof($this->_file);
  21339.       else
  21340.         $v_end_of_file = @feof($this->_file);
  21341.         */
  21342.  
  21343.       if ($v_listing || $v_extract_file || $v_extraction_stopped) {
  21344.         // ----- Log extracted files
  21345.         if (($v_file_dir = dirname($v_header['filename']))
  21346.             == $v_header['filename'])
  21347.           $v_file_dir = '';
  21348.         if ((substr($v_header['filename'], 0, 1) == '/') && ($v_file_dir == ''))
  21349.           $v_file_dir = '/';
  21350.  
  21351.         $p_list_detail[$v_nb++] = $v_header;
  21352.         if (is_array($p_file_list) && (count($p_list_detail) == count($p_file_list))) {
  21353.             return true;
  21354.         }
  21355.       }
  21356.     }
  21357.  
  21358.         return true;
  21359.     }
  21360.     // }}}
  21361.  
  21362.     // {{{ _openAppend()
  21363.     function _openAppend()
  21364.     {
  21365.         if (filesize($this->_tarname) == 0)
  21366.           return $this->_openWrite();
  21367.           
  21368.         if ($this->_compress) {
  21369.             $this->_close();
  21370.  
  21371.             if (!@rename($this->_tarname, $this->_tarname.".tmp")) {
  21372.                 $this->_error('Error while renaming \''.$this->_tarname
  21373.                               .'\' to temporary file \''.$this->_tarname
  21374.                               .'.tmp\'');
  21375.                 return false;
  21376.             }
  21377.  
  21378.             if ($this->_compress_type == 'gz')
  21379.                 $v_temp_tar = @gzopen($this->_tarname.".tmp", "rb");
  21380.             elseif ($this->_compress_type == 'bz2')
  21381.                 $v_temp_tar = @bzopen($this->_tarname.".tmp", "rb");
  21382.                 
  21383.             if ($v_temp_tar == 0) {
  21384.                 $this->_error('Unable to open file \''.$this->_tarname
  21385.                               .'.tmp\' in binary read mode');
  21386.                 @rename($this->_tarname.".tmp", $this->_tarname);
  21387.                 return false;
  21388.             }
  21389.  
  21390.             if (!$this->_openWrite()) {
  21391.                 @rename($this->_tarname.".tmp", $this->_tarname);
  21392.                 return false;
  21393.             }
  21394.  
  21395.             if ($this->_compress_type == 'gz') {
  21396.                 while (!@gzeof($v_temp_tar)) {
  21397.                     $v_buffer = @gzread($v_temp_tar, 512);
  21398.                     if ($v_buffer == ARCHIVE_TAR_END_BLOCK) {
  21399.                         // do not copy end blocks, we will re-make them
  21400.                         // after appending
  21401.                         continue;
  21402.                     }
  21403.                     $v_binary_data = pack("a512", $v_buffer);
  21404.                     $this->_writeBlock($v_binary_data);
  21405.                 }
  21406.  
  21407.                 @gzclose($v_temp_tar);
  21408.             }
  21409.             elseif ($this->_compress_type == 'bz2') {
  21410.                 while (strlen($v_buffer = @bzread($v_temp_tar, 512)) > 0) {
  21411.                     if ($v_buffer == ARCHIVE_TAR_END_BLOCK) {
  21412.                         continue;
  21413.                     }
  21414.                     $v_binary_data = pack("a512", $v_buffer);
  21415.                     $this->_writeBlock($v_binary_data);
  21416.                 }
  21417.  
  21418.                 @bzclose($v_temp_tar);
  21419.             }
  21420.  
  21421.             if (!@unlink($this->_tarname.".tmp")) {
  21422.                 $this->_error('Error while deleting temporary file \''
  21423.                               .$this->_tarname.'.tmp\'');
  21424.             }
  21425.  
  21426.         } else {
  21427.             // ----- For not compressed tar, just add files before the last
  21428.             //       one or two 512 bytes block
  21429.             if (!$this->_openReadWrite())
  21430.                return false;
  21431.  
  21432.             clearstatcache();
  21433.             $v_size = filesize($this->_tarname);
  21434.  
  21435.             // We might have zero, one or two end blocks.
  21436.             // The standard is two, but we should try to handle 
  21437.             // other cases.
  21438.             fseek($this->_file, $v_size - 1024);
  21439.             if (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) {
  21440.                 fseek($this->_file, $v_size - 1024);
  21441.             }
  21442.             elseif (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) {
  21443.                 fseek($this->_file, $v_size - 512);    
  21444.             }
  21445.         }
  21446.  
  21447.         return true;
  21448.     }
  21449.     // }}}
  21450.  
  21451.     // {{{ _append()
  21452.     function _append($p_filelist, $p_add_dir='', $p_remove_dir='')
  21453.     {
  21454.         if (!$this->_openAppend())
  21455.             return false;
  21456.             
  21457.         if ($this->_addList($p_filelist, $p_add_dir, $p_remove_dir))
  21458.            $this->_writeFooter();
  21459.  
  21460.         $this->_close();
  21461.  
  21462.         return true;
  21463.     }
  21464.     // }}}
  21465.  
  21466.     // {{{ _dirCheck()
  21467.  
  21468.     /**
  21469.      * Check if a directory exists and create it (including parent
  21470.      * dirs) if not.
  21471.      *
  21472.      * @param string $p_dir directory to check
  21473.      *
  21474.      * @return bool TRUE if the directory exists or was created
  21475.      */
  21476.     function _dirCheck($p_dir)
  21477.     {
  21478.         clearstatcache();
  21479.         if ((@is_dir($p_dir)) || ($p_dir == ''))
  21480.             return true;
  21481.  
  21482.         $p_parent_dir = dirname($p_dir);
  21483.  
  21484.         if (($p_parent_dir != $p_dir) &&
  21485.             ($p_parent_dir != '') &&
  21486.             (!$this->_dirCheck($p_parent_dir)))
  21487.              return false;
  21488.  
  21489.         if (!@mkdir($p_dir, 0777)) {
  21490.             $this->_error("Unable to create directory '$p_dir'");
  21491.             return false;
  21492.         }
  21493.  
  21494.         return true;
  21495.     }
  21496.  
  21497.     // }}}
  21498.  
  21499.     // {{{ _pathReduction()
  21500.  
  21501.     /**
  21502.      * Compress path by changing for example "/dir/foo/../bar" to "/dir/bar", 
  21503.      * rand emove double slashes.
  21504.      *
  21505.      * @param string $p_dir path to reduce
  21506.      *
  21507.      * @return string reduced path
  21508.      *
  21509.      * @access private
  21510.      *
  21511.      */
  21512.     function _pathReduction($p_dir)
  21513.     {
  21514.         $v_result = '';
  21515.  
  21516.         // ----- Look for not empty path
  21517.         if ($p_dir != '') {
  21518.             // ----- Explode path by directory names
  21519.             $v_list = explode('/', $p_dir);
  21520.  
  21521.             // ----- Study directories from last to first
  21522.             for ($i=sizeof($v_list)-1; $i>=0; $i--) {
  21523.                 // ----- Look for current path
  21524.                 if ($v_list[$i] == ".") {
  21525.                     // ----- Ignore this directory
  21526.                     // Should be the first $i=0, but no check is done
  21527.                 }
  21528.                 else if ($v_list[$i] == "..") {
  21529.                     // ----- Ignore it and ignore the $i-1
  21530.                     $i--;
  21531.                 }
  21532.                 else if (   ($v_list[$i] == '')
  21533.                          && ($i!=(sizeof($v_list)-1))
  21534.                          && ($i!=0)) {
  21535.                     // ----- Ignore only the double '//' in path,
  21536.                     // but not the first and last /
  21537.                 } else {
  21538.                     $v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?'/'
  21539.                                 .$v_result:'');
  21540.                 }
  21541.             }
  21542.         }
  21543.         $v_result = strtr($v_result, '\\', '/');
  21544.         return $v_result;
  21545.     }
  21546.  
  21547.     // }}}
  21548.  
  21549.     // {{{ _translateWinPath()
  21550.     function _translateWinPath($p_path, $p_remove_disk_letter=true)
  21551.     {
  21552.       if (defined('OS_WINDOWS') && OS_WINDOWS) {
  21553.           // ----- Look for potential disk letter
  21554.           if (   ($p_remove_disk_letter)
  21555.               && (($v_position = strpos($p_path, ':')) != false)) {
  21556.               $p_path = substr($p_path, $v_position+1);
  21557.           }
  21558.           // ----- Change potential windows directory separator
  21559.           if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0,1) == '\\')) {
  21560.               $p_path = strtr($p_path, '\\', '/');
  21561.           }
  21562.       }
  21563.       return $p_path;
  21564.     }
  21565.     // }}}
  21566.  
  21567. }
  21568. ?>
  21569. Archive_Tar-1.3.2/docs/Archive_Tar.txt100644   1750   1750       43673 10547623416  13053 Documentation for class Archive_Tar
  21570. ===================================
  21571. Last update : 2001-08-15
  21572.  
  21573.  
  21574.  
  21575. Overview :
  21576. ----------
  21577.  
  21578.   The Archive_Tar class helps in creating and managing GNU TAR format
  21579.   files compressed by GNU ZIP or not. 
  21580.   The class offers basic functions like creating an archive, adding
  21581.   files in the archive, extracting files from the archive and listing
  21582.   the archive content. 
  21583.   It also provide advanced functions that allow the adding and
  21584.   extraction of files with path manipulation. 
  21585.  
  21586.  
  21587. Sample :
  21588. --------
  21589.  
  21590.   // ----- Creating the object (uncompressed archive)
  21591.   $tar_object = new Archive_Tar("tarname.tar");
  21592.   $tar_object->setErrorHandling(PEAR_ERROR_PRINT);
  21593.  
  21594.   // ----- Creating the archive
  21595.   $v_list[0]="file.txt";
  21596.   $v_list[1]="data/";
  21597.   $v_list[2]="file.log";
  21598.   $tar_object->create($v_list);
  21599.  
  21600.   // ----- Adding files
  21601.   $v_list[0]="dev/file.txt";
  21602.   $v_list[1]="dev/data/";
  21603.   $v_list[2]="log/file.log";
  21604.   $tar_object->add($v_list);
  21605.  
  21606.   // ----- Adding more files
  21607.   $tar_object->add("release/newfile.log release/readme.txt");
  21608.  
  21609.   // ----- Listing the content
  21610.   if (($v_list  =  $tar_object->listContent()) != 0)
  21611.     for ($i=0; $i<sizeof($v_list); $i++)
  21612.     {
  21613.       echo "Filename :'".$v_list[$i][filename]."'<br>";
  21614.       echo " .size :'".$v_list[$i][size]."'<br>";
  21615.       echo " .mtime :'".$v_list[$i][mtime]."' (".date("l dS of F Y h:i:s A", $v_list[$i][mtime]).")<br>";
  21616.       echo " .mode :'".$v_list[$i][mode]."'<br>";
  21617.       echo " .uid :'".$v_list[$i][uid]."'<br>";
  21618.       echo " .gid :'".$v_list[$i][gid]."'<br>";
  21619.       echo " .typeflag :'".$v_list[$i][typeflag]."'<br>";
  21620.     }
  21621.  
  21622.   // ----- Extracting the archive in directory "install"
  21623.   $tar_object->extract("install");
  21624.  
  21625.  
  21626. Public arguments :
  21627. ------------------
  21628.  
  21629. None
  21630.  
  21631.  
  21632. Public Methods :
  21633. ----------------
  21634.  
  21635. Method : Archive_Tar($p_tarname, $compress = null)
  21636. Description :
  21637.   Archive_Tar Class constructor. This flavour of the constructor only
  21638.   declare a new Archive_Tar object, identifying it by the name of the
  21639.   tar file.
  21640.   If the compress argument is set the tar will be read or created as a
  21641.   gzip or bz2 compressed TAR file. 
  21642. Arguments :
  21643.   $p_tarname : A valid filename for the tar archive file.
  21644.   $p_compress : can be null, 'gz' or 'bz2'. For
  21645.                 compatibility reason it can also be true. This
  21646.                 parameter indicates if gzip or bz2 compression
  21647.                 is required. 
  21648. Return value :
  21649.   The Archive_Tar object.
  21650. Sample :
  21651.   $tar_object = new Archive_Tar("tarname.tar");
  21652.   $tar_object_compressed = new Archive_Tar("tarname.tgz", true);
  21653. How it works :
  21654.   Initialize the object.
  21655.  
  21656. Method : create($p_filelist)
  21657. Description :
  21658.   This method creates the archive file and add the files / directories
  21659.   that are listed in $p_filelist. 
  21660.   If the file already exists and is writable, it is replaced by the
  21661.   new tar. It is a create and not an add. If the file exists and is
  21662.   read-only or is a directory it is not replaced. The method return
  21663.   false and a PEAR error text. 
  21664.   The $p_filelist parameter can be an array of string, each string
  21665.   representing a filename or a directory name with their path if
  21666.   needed. It can also be a single string with names separated by a
  21667.   single blank. 
  21668.   See also createModify() method for more details.
  21669. Arguments :
  21670.   $p_filelist : An array of filenames and directory names, or a single
  21671.   string with names separated by a single blank space. 
  21672. Return value :
  21673.   true on success, false on error.
  21674. Sample 1 :
  21675.   $tar_object = new Archive_Tar("tarname.tar");
  21676.   $tar_object->setErrorHandling(PEAR_ERROR_PRINT);  // Optional error handling
  21677.   $v_list[0]="file.txt";
  21678.   $v_list[1]="data/"; (Optional '/' at the end)
  21679.   $v_list[2]="file.log";
  21680.   $tar_object->create($v_list);
  21681. Sample 2 :
  21682.   $tar_object = new Archive_Tar("tarname.tar");
  21683.   $tar_object->setErrorHandling(PEAR_ERROR_PRINT);  // Optional error handling
  21684.   $tar_object->create("file.txt data/ file.log");
  21685. How it works :
  21686.   Just calling the createModify() method with the right parameters.
  21687.  
  21688. Method : createModify($p_filelist, $p_add_dir, $p_remove_dir = "")
  21689. Description :
  21690.   This method creates the archive file and add the files / directories
  21691.   that are listed in $p_filelist. 
  21692.   If the file already exists and is writable, it is replaced by the
  21693.   new tar. It is a create and not an add. If the file exists and is
  21694.   read-only or is a directory it is not replaced. The method return
  21695.   false and a PEAR error text. 
  21696.   The $p_filelist parameter can be an array of string, each string
  21697.   representing a filename or a directory name with their path if
  21698.   needed. It can also be a single string with names separated by a
  21699.   single blank. 
  21700.   The path indicated in $p_remove_dir will be removed from the
  21701.   memorized path of each file / directory listed when this path
  21702.   exists. By default nothing is removed (empty path "") 
  21703.   The path indicated in $p_add_dir will be added at the beginning of
  21704.   the memorized path of each file / directory listed. However it can
  21705.   be set to empty "". The adding of a path is done after the removing
  21706.   of path. 
  21707.   The path add/remove ability enables the user to prepare an archive
  21708.   for extraction in a different path than the origin files are. 
  21709.   See also addModify() method for file adding properties.
  21710. Arguments :
  21711.   $p_filelist : An array of filenames and directory names, or a single
  21712.                 string with names separated by a single blank space.
  21713.   $p_add_dir : A string which contains a path to be added to the
  21714.                memorized path of each element in the list. 
  21715.   $p_remove_dir : A string which contains a path to be removed from
  21716.                   the memorized path of each element in the list, when
  21717.           relevant.
  21718. Return value :
  21719.   true on success, false on error.
  21720. Sample 1 :
  21721.   $tar_object = new Archive_Tar("tarname.tar");
  21722.   $tar_object->setErrorHandling(PEAR_ERROR_PRINT);  // Optional error handling
  21723.   $v_list[0]="file.txt";
  21724.   $v_list[1]="data/"; (Optional '/' at the end)
  21725.   $v_list[2]="file.log";
  21726.   $tar_object->createModify($v_list, "install");
  21727.   // files are stored in the archive as :
  21728.   //   install/file.txt
  21729.   //   install/data
  21730.   //   install/data/file1.txt
  21731.   //   install/data/... all the files and sub-dirs of data/
  21732.   //   install/file.log
  21733. Sample 2 :
  21734.   $tar_object = new Archive_Tar("tarname.tar");
  21735.   $tar_object->setErrorHandling(PEAR_ERROR_PRINT);  // Optional error handling
  21736.   $v_list[0]="dev/file.txt";
  21737.   $v_list[1]="dev/data/"; (Optional '/' at the end)
  21738.   $v_list[2]="log/file.log";
  21739.   $tar_object->createModify($v_list, "install", "dev");
  21740.   // files are stored in the archive as :
  21741.   //   install/file.txt
  21742.   //   install/data
  21743.   //   install/data/file1.txt
  21744.   //   install/data/... all the files and sub-dirs of data/
  21745.   //   install/log/file.log
  21746. How it works :
  21747.   Open the file in write mode (erasing the existing one if one),
  21748.   call the _addList() method for adding the files in an empty archive,
  21749.   add the tar footer (512 bytes block), close the tar file.
  21750.  
  21751.  
  21752. Method : addModify($p_filelist, $p_add_dir, $p_remove_dir="")
  21753. Description :
  21754.   This method add the files / directories listed in $p_filelist at the
  21755.   end of the existing archive. If the archive does not yet exists it
  21756.   is created.
  21757.   The $p_filelist parameter can be an array of string, each string
  21758.   representing a filename or a directory name with their path if
  21759.   needed. It can also be a single string with names separated by a
  21760.   single blank. 
  21761.   The path indicated in $p_remove_dir will be removed from the
  21762.   memorized path of each file / directory listed when this path
  21763.   exists. By default nothing is removed (empty path "") 
  21764.   The path indicated in $p_add_dir will be added at the beginning of
  21765.   the memorized path of each file / directory listed. However it can
  21766.   be set to empty "". The adding of a path is done after the removing
  21767.   of path. 
  21768.   The path add/remove ability enables the user to prepare an archive
  21769.   for extraction in a different path than the origin files are. 
  21770.   If a file/dir is already in the archive it will only be added at the
  21771.   end of the archive. There is no update of the existing archived
  21772.   file/dir. However while extracting the archive, the last file will
  21773.   replace the first one. This results in a none optimization of the
  21774.   archive size. 
  21775.   If a file/dir does not exist the file/dir is ignored. However an
  21776.   error text is send to PEAR error. 
  21777.   If a file/dir is not readable the file/dir is ignored. However an
  21778.   error text is send to PEAR error. 
  21779.   If the resulting filename/dirname (after the add/remove option or
  21780.   not) string is greater than 99 char, the file/dir is
  21781.   ignored. However an error text is send to PEAR error. 
  21782. Arguments :
  21783.   $p_filelist : An array of filenames and directory names, or a single
  21784.                 string with names separated by a single blank space. 
  21785.   $p_add_dir : A string which contains a path to be added to the
  21786.                memorized path of each element in the list. 
  21787.   $p_remove_dir : A string which contains a path to be removed from
  21788.                   the memorized path of each element in the list, when
  21789.           relevant.
  21790. Return value :
  21791.   true on success, false on error.
  21792. Sample 1 :
  21793.   $tar_object = new Archive_Tar("tarname.tar");
  21794.   [...]
  21795.   $v_list[0]="dev/file.txt";
  21796.   $v_list[1]="dev/data/"; (Optional '/' at the end)
  21797.   $v_list[2]="log/file.log";
  21798.   $tar_object->addModify($v_list, "install");
  21799.   // files are stored in the archive as :
  21800.   //   install/file.txt
  21801.   //   install/data
  21802.   //   install/data/file1.txt
  21803.   //   install/data/... all the files and sub-dirs of data/
  21804.   //   install/file.log
  21805. Sample 2 :
  21806.   $tar_object = new Archive_Tar("tarname.tar");
  21807.   [...]
  21808.   $v_list[0]="dev/file.txt";
  21809.   $v_list[1]="dev/data/"; (Optional '/' at the end)
  21810.   $v_list[2]="log/file.log";
  21811.   $tar_object->addModify($v_list, "install", "dev");
  21812.   // files are stored in the archive as :
  21813.   //   install/file.txt
  21814.   //   install/data
  21815.   //   install/data/file1.txt
  21816.   //   install/data/... all the files and sub-dirs of data/
  21817.   //   install/log/file.log
  21818. How it works :
  21819.   If the archive does not exists it create it and add the files.
  21820.   If the archive does exists and is not compressed, it open it, jump
  21821.   before the last empty 512 bytes block (tar footer) and add the files
  21822.   at this point.
  21823.   If the archive does exists and is compressed, a temporary copy file
  21824.   is created. This temporary file is then 'gzip' read block by block
  21825.   until the last empty block. The new files are then added in the
  21826.   compressed file.
  21827.   The adding of files is done by going through the file/dir list,
  21828.   adding files per files, in a recursive way through the
  21829.   directory. Each time a path need to be added/removed it is done
  21830.   before writing the file header in the archive.
  21831.  
  21832. Method : add($p_filelist)
  21833. Description :
  21834.   This method add the files / directories listed in $p_filelist at the
  21835.   end of the existing archive. If the archive does not yet exists it
  21836.   is created. 
  21837.   The $p_filelist parameter can be an array of string, each string
  21838.   representing a filename or a directory name with their path if
  21839.   needed. It can also be a single string with names separated by a
  21840.   single blank. 
  21841.   See addModify() method for details and limitations.
  21842. Arguments :
  21843.   $p_filelist : An array of filenames and directory names, or a single
  21844.   string with names separated by a single blank space. 
  21845. Return value :
  21846.   true on success, false on error.
  21847. Sample 1 :
  21848.   $tar_object = new Archive_Tar("tarname.tar");
  21849.   [...]
  21850.   $v_list[0]="dev/file.txt";
  21851.   $v_list[1]="dev/data/"; (Optional '/' at the end)
  21852.   $v_list[2]="log/file.log";
  21853.   $tar_object->add($v_list);
  21854. Sample 2 :
  21855.   $tar_object = new Archive_Tar("tarname.tgz", true);
  21856.   [...]
  21857.   $v_list[0]="dev/file.txt";
  21858.   $v_list[1]="dev/data/"; (Optional '/' at the end)
  21859.   $v_list[2]="log/file.log";
  21860.   $tar_object->add($v_list);
  21861. How it works :
  21862.   Simply call the addModify() method with the right parameters.
  21863.  
  21864. Method : addString($p_filename, $p_string)
  21865. Description :
  21866.   This method add a single string as a file at the
  21867.   end of the existing archive. If the archive does not yet exists it
  21868.   is created.
  21869. Arguments :
  21870.   $p_filename : A string which contains the full filename path
  21871.                 that will be associated with the string.
  21872.   $p_string :   The content of the file added in the archive.
  21873. Return value :
  21874.   true on success, false on error.
  21875. Sample 1 :
  21876.   $v_archive = & new Archive_Tar($p_filename);
  21877.   $v_archive->setErrorHandling(PEAR_ERROR_PRINT);
  21878.   $v_result = $v_archive->addString('data/test.txt', 'This is the text of the string');
  21879.  
  21880.  
  21881. Method : extract($p_path = "")
  21882. Description :
  21883.   This method extract all the content of the archive in the directory
  21884.   indicated by $p_path.If $p_path is optional, if not set the archive
  21885.   is extracted in the current directory. 
  21886.   While extracting a file, if the directory path does not exists it is
  21887.   created. 
  21888.   See extractModify() for details and limitations.
  21889. Arguments :
  21890.   $p_path : Optional path where the files/dir need to by extracted.
  21891. Return value :
  21892.   true on success, false on error.
  21893. Sample :
  21894.   $tar_object = new Archive_Tar("tarname.tar");
  21895.   $tar_object->extract();
  21896. How it works :
  21897.   Simply call the extractModify() method with appropriate parameters.
  21898.  
  21899. Method : extractModify($p_path, $p_remove_path)
  21900. Description :
  21901.   This method extract all the content of the archive in the directory
  21902.   indicated by $p_path. When relevant the memorized path of the
  21903.   files/dir can be modified by removing the $p_remove_path path at the
  21904.   beginning of the file/dir path. 
  21905.   While extracting a file, if the directory path does not exists it is
  21906.   created. 
  21907.   While extracting a file, if the file already exists it is replaced
  21908.   without looking for last modification date. 
  21909.   While extracting a file, if the file already exists and is write
  21910.   protected, the extraction is aborted. 
  21911.   While extracting a file, if a directory with the same name already
  21912.   exists, the extraction is aborted. 
  21913.   While extracting a directory, if a file with the same name already
  21914.   exists, the extraction is aborted. 
  21915.   While extracting a file/directory if the destination directory exist
  21916.   and is write protected, or does not exist but can not be created,
  21917.   the extraction is aborted. 
  21918.   If after extraction an extracted file does not show the correct
  21919.   stored file size, the extraction is aborted. 
  21920.   When the extraction is aborted, a PEAR error text is set and false
  21921.   is returned. However the result can be a partial extraction that may
  21922.   need to be manually cleaned. 
  21923. Arguments :
  21924.   $p_path : The path of the directory where the files/dir need to by
  21925.             extracted. 
  21926.   $p_remove_path : Part of the memorized path that can be removed if
  21927.                    present at the beginning of the file/dir path. 
  21928. Return value :
  21929.   true on success, false on error.
  21930. Sample :
  21931.   // Imagine tarname.tar with files :
  21932.   //   dev/data/file.txt
  21933.   //   dev/data/log.txt
  21934.   //   readme.txt
  21935.   $tar_object = new Archive_Tar("tarname.tar");
  21936.   $tar_object->extractModify("install", "dev");
  21937.   // Files will be extracted there :
  21938.   //   install/data/file.txt
  21939.   //   install/data/log.txt
  21940.   //   install/readme.txt
  21941. How it works :
  21942.   Open the archive and call a more generic function that can extract
  21943.   only a part of the archive or all the archive. 
  21944.   See extractList() method for more details.
  21945.  
  21946. Method : extractInString($p_filename)
  21947. Description :
  21948.   This method extract from the archive one file identified by $p_filename.
  21949.   The return value is a string with the file content, or NULL on error. 
  21950. Arguments :
  21951.   $p_filename : The path of the file to extract in a string. 
  21952. Return value :
  21953.   a string with the file content or NULL.
  21954. Sample :
  21955.   // Imagine tarname.tar with files :
  21956.   //   dev/data/file.txt
  21957.   //   dev/data/log.txt
  21958.   //   dev/readme.txt
  21959.   $v_archive = & new Archive_Tar('tarname.tar');
  21960.   $v_archive->setErrorHandling(PEAR_ERROR_PRINT);
  21961.   $v_string = $v_archive->extractInString('dev/readme.txt');
  21962.   echo $v_string;
  21963.  
  21964. Method : listContent()
  21965. Description :
  21966.   This method returns an array of arrays that describe each
  21967.   file/directory present in the archive. 
  21968.   The array is not sorted, so it show the position of the file in the
  21969.   archive. 
  21970.   The file informations are :
  21971.     $file[filename] : Name and path of the file/dir.
  21972.     $file[mode] : File permissions (result of fileperms())
  21973.     $file[uid] : user id
  21974.     $file[gid] : group id
  21975.     $file[size] : filesize
  21976.     $file[mtime] : Last modification time (result of filemtime())
  21977.     $file[typeflag] : "" for file, "5" for directory
  21978. Arguments :
  21979. Return value :
  21980.   An array of arrays or 0 on error.
  21981. Sample :
  21982.   $tar_object = new Archive_Tar("tarname.tar");
  21983.   if (($v_list  =  $tar_object->listContent()) != 0)
  21984.     for ($i=0; $i<sizeof($v_list); $i++)
  21985.     {
  21986.       echo "Filename :'".$v_list[$i][filename]."'<br>";
  21987.       echo " .size :'".$v_list[$i][size]."'<br>";
  21988.       echo " .mtime :'".$v_list[$i][mtime]."' (".
  21989.            date("l dS of F Y h:i:s A", $v_list[$i][mtime]).")<br>";
  21990.       echo " .mode :'".$v_list[$i][mode]."'<br>";
  21991.       echo " .uid :'".$v_list[$i][uid]."'<br>";
  21992.       echo " .gid :'".$v_list[$i][gid]."'<br>";
  21993.       echo " .typeflag :'".$v_list[$i][typeflag]."'<br>";
  21994.     }
  21995. How it works :
  21996.   Call the same function as an extract however with a flag to only go
  21997.   through the archive without extracting the files. 
  21998.  
  21999. Method : extractList($p_filelist, $p_path = "", $p_remove_path = "")
  22000. Description :
  22001.   This method extract from the archive only the files indicated in the
  22002.   $p_filelist. These files are extracted in the current directory or
  22003.   in the directory indicated by the optional $p_path parameter. 
  22004.   If indicated the $p_remove_path can be used in the same way as it is
  22005.   used in extractModify() method. 
  22006. Arguments :
  22007.   $p_filelist : An array of filenames and directory names, or a single
  22008.                 string with names separated by a single blank space. 
  22009.   $p_path : The path of the directory where the files/dir need to by
  22010.             extracted. 
  22011.   $p_remove_path : Part of the memorized path that can be removed if
  22012.                    present at the beginning of the file/dir path. 
  22013. Return value :
  22014.   true on success, false on error.
  22015. Sample :
  22016.   // Imagine tarname.tar with files :
  22017.   //   dev/data/file.txt
  22018.   //   dev/data/log.txt
  22019.   //   readme.txt
  22020.   $tar_object = new Archive_Tar("tarname.tar");
  22021.   $tar_object->extractList("dev/data/file.txt readme.txt", "install",
  22022.                            "dev");
  22023.   // Files will be extracted there :
  22024.   //   install/data/file.txt
  22025.   //   install/readme.txt
  22026. How it works :
  22027.   Go through the archive and extract only the files present in the
  22028.   list. 
  22029.  
  22030. package.xml100644   1750   1750       10425 10633574607   6452 <?xml version="1.0" encoding="UTF-8"?>
  22031. <package packagerversion="1.6.1" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
  22032.  <name>Console_Getopt</name>
  22033.  <channel>pear.php.net</channel>
  22034.  <summary>Command-line option parser</summary>
  22035.  <description>This is a PHP implementation of "getopt" supporting both
  22036. short and long options.</description>
  22037.  <lead>
  22038.   <name>Andrei Zmievski</name>
  22039.   <user>andrei</user>
  22040.   <email>andrei@php.net</email>
  22041.   <active>yes</active>
  22042.  </lead>
  22043.  <developer>
  22044.   <name>Stig Bakken</name>
  22045.   <user>ssb</user>
  22046.   <email>stig@php.net</email>
  22047.   <active>no</active>
  22048.  </developer>
  22049.  <helper>
  22050.   <name>Greg Beaver</name>
  22051.   <user>cellog</user>
  22052.   <email>cellog@php.net</email>
  22053.   <active>yes</active>
  22054.  </helper>
  22055.  <date>2007-06-12</date>
  22056.  <time>14:52:39</time>
  22057.  <version>
  22058.   <release>1.2.3</release>
  22059.   <api>1.2.1</api>
  22060.  </version>
  22061.  <stability>
  22062.   <release>stable</release>
  22063.   <api>stable</api>
  22064.  </stability>
  22065.  <license uri="http://www.php.net/license">PHP License</license>
  22066.  <notes>* fix Bug #11068: No way to read plain "-" option [cardoe]</notes>
  22067.  <contents>
  22068.   <dir name="/">
  22069.    <file md5sum="f2175a45c5e5bc7c97e174bdae55b671" name="Console/Getopt.php" role="php" />
  22070.   </dir>
  22071.  </contents>
  22072.  <compatible>
  22073.   <name>PEAR</name>
  22074.   <channel>pear.php.net</channel>
  22075.   <min>1.4.0</min>
  22076.   <max>1.6.0</max>
  22077.  </compatible>
  22078.  <dependencies>
  22079.   <required>
  22080.    <php>
  22081.     <min>4.3.0</min>
  22082.    </php>
  22083.    <pearinstaller>
  22084.     <min>1.4.3</min>
  22085.    </pearinstaller>
  22086.   </required>
  22087.  </dependencies>
  22088.  <phprelease />
  22089.  <changelog>
  22090.   <release>
  22091.    <version>
  22092.     <release>1.2.2</release>
  22093.     <api>1.2.1</api>
  22094.    </version>
  22095.    <stability>
  22096.     <release>stable</release>
  22097.     <api>stable</api>
  22098.    </stability>
  22099.    <date>2007-02-17</date>
  22100.    <license uri="http://www.php.net/license">PHP License</license>
  22101.    <notes>* fix Bug #4475: An ambiguous error occurred when specifying similar longoption name.
  22102. * fix Bug #10055: Not failing properly on short options missing required values</notes>
  22103.   </release>
  22104.   <release>
  22105.    <version>
  22106.     <release>1.2.1</release>
  22107.     <api>1.2.1</api>
  22108.    </version>
  22109.    <stability>
  22110.     <release>stable</release>
  22111.     <api>stable</api>
  22112.    </stability>
  22113.    <date>2006-12-08</date>
  22114.    <license uri="http://www.php.net/license">PHP License</license>
  22115.    <notes>Fixed bugs #4448 (Long parameter values truncated with longoption parameter) and #7444 (Trailing spaces after php closing tag)</notes>
  22116.   </release>
  22117.   <release>
  22118.    <version>
  22119.     <release>1.2</release>
  22120.     <api>1.2</api>
  22121.    </version>
  22122.    <stability>
  22123.     <release>stable</release>
  22124.     <api>stable</api>
  22125.    </stability>
  22126.    <date>2003-12-11</date>
  22127.    <license uri="http://www.php.net/license">PHP License</license>
  22128.    <notes>Fix to preserve BC with 1.0 and allow correct behaviour for new users</notes>
  22129.   </release>
  22130.   <release>
  22131.    <version>
  22132.     <release>1.0</release>
  22133.     <api>1.0</api>
  22134.    </version>
  22135.    <stability>
  22136.     <release>stable</release>
  22137.     <api>stable</api>
  22138.    </stability>
  22139.    <date>2002-09-13</date>
  22140.    <license uri="http://www.php.net/license">PHP License</license>
  22141.    <notes>Stable release</notes>
  22142.   </release>
  22143.   <release>
  22144.    <version>
  22145.     <release>0.11</release>
  22146.     <api>0.11</api>
  22147.    </version>
  22148.    <stability>
  22149.     <release>beta</release>
  22150.     <api>beta</api>
  22151.    </stability>
  22152.    <date>2002-05-26</date>
  22153.    <license uri="http://www.php.net/license">PHP License</license>
  22154.    <notes>POSIX getopt compatibility fix: treat first element of args
  22155.         array as command name</notes>
  22156.   </release>
  22157.   <release>
  22158.    <version>
  22159.     <release>0.10</release>
  22160.     <api>0.10</api>
  22161.    </version>
  22162.    <stability>
  22163.     <release>beta</release>
  22164.     <api>beta</api>
  22165.    </stability>
  22166.    <date>2002-05-12</date>
  22167.    <license uri="http://www.php.net/license">PHP License</license>
  22168.    <notes>Packaging fix</notes>
  22169.   </release>
  22170.   <release>
  22171.    <version>
  22172.     <release>0.9</release>
  22173.     <api>0.9</api>
  22174.    </version>
  22175.    <stability>
  22176.     <release>beta</release>
  22177.     <api>beta</api>
  22178.    </stability>
  22179.    <date>2002-05-12</date>
  22180.    <license uri="http://www.php.net/license">PHP License</license>
  22181.    <notes>Initial release</notes>
  22182.   </release>
  22183.  </changelog>
  22184. </package>
  22185. Console_Getopt-1.2.3/Console/Getopt.php100644   1750   1750       25332 10633574607  13300 <?php
  22186. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  22187. // +----------------------------------------------------------------------+
  22188. // | PHP Version 5                                                        |
  22189. // +----------------------------------------------------------------------+
  22190. // | Copyright (c) 1997-2004 The PHP Group                                |
  22191. // +----------------------------------------------------------------------+
  22192. // | This source file is subject to version 3.0 of the PHP license,       |
  22193. // | that is bundled with this package in the file LICENSE, and is        |
  22194. // | available through the world-wide-web at the following url:           |
  22195. // | http://www.php.net/license/3_0.txt.                                  |
  22196. // | If you did not receive a copy of the PHP license and are unable to   |
  22197. // | obtain it through the world-wide-web, please send a note to          |
  22198. // | license@php.net so we can mail you a copy immediately.               |
  22199. // +----------------------------------------------------------------------+
  22200. // | Author: Andrei Zmievski <andrei@php.net>                             |
  22201. // +----------------------------------------------------------------------+
  22202. //
  22203. // $Id: Getopt.php,v 1.4 2007/06/12 14:58:56 cellog Exp $
  22204.  
  22205. require_once 'PEAR.php';
  22206.  
  22207. /**
  22208.  * Command-line options parsing class.
  22209.  *
  22210.  * @author Andrei Zmievski <andrei@php.net>
  22211.  *
  22212.  */
  22213. class Console_Getopt {
  22214.     /**
  22215.      * Parses the command-line options.
  22216.      *
  22217.      * The first parameter to this function should be the list of command-line
  22218.      * arguments without the leading reference to the running program.
  22219.      *
  22220.      * The second parameter is a string of allowed short options. Each of the
  22221.      * option letters can be followed by a colon ':' to specify that the option
  22222.      * requires an argument, or a double colon '::' to specify that the option
  22223.      * takes an optional argument.
  22224.      *
  22225.      * The third argument is an optional array of allowed long options. The
  22226.      * leading '--' should not be included in the option name. Options that
  22227.      * require an argument should be followed by '=', and options that take an
  22228.      * option argument should be followed by '=='.
  22229.      *
  22230.      * The return value is an array of two elements: the list of parsed
  22231.      * options and the list of non-option command-line arguments. Each entry in
  22232.      * the list of parsed options is a pair of elements - the first one
  22233.      * specifies the option, and the second one specifies the option argument,
  22234.      * if there was one.
  22235.      *
  22236.      * Long and short options can be mixed.
  22237.      *
  22238.      * Most of the semantics of this function are based on GNU getopt_long().
  22239.      *
  22240.      * @param array  $args           an array of command-line arguments
  22241.      * @param string $short_options  specifies the list of allowed short options
  22242.      * @param array  $long_options   specifies the list of allowed long options
  22243.      *
  22244.      * @return array two-element array containing the list of parsed options and
  22245.      * the non-option arguments
  22246.      *
  22247.      * @access public
  22248.      *
  22249.      */
  22250.     function getopt2($args, $short_options, $long_options = null)
  22251.     {
  22252.         return Console_Getopt::doGetopt(2, $args, $short_options, $long_options);
  22253.     }
  22254.  
  22255.     /**
  22256.      * This function expects $args to start with the script name (POSIX-style).
  22257.      * Preserved for backwards compatibility.
  22258.      * @see getopt2()
  22259.      */    
  22260.     function getopt($args, $short_options, $long_options = null)
  22261.     {
  22262.         return Console_Getopt::doGetopt(1, $args, $short_options, $long_options);
  22263.     }
  22264.  
  22265.     /**
  22266.      * The actual implementation of the argument parsing code.
  22267.      */
  22268.     function doGetopt($version, $args, $short_options, $long_options = null)
  22269.     {
  22270.         // in case you pass directly readPHPArgv() as the first arg
  22271.         if (PEAR::isError($args)) {
  22272.             return $args;
  22273.         }
  22274.         if (empty($args)) {
  22275.             return array(array(), array());
  22276.         }
  22277.         $opts     = array();
  22278.         $non_opts = array();
  22279.  
  22280.         settype($args, 'array');
  22281.  
  22282.         if ($long_options) {
  22283.             sort($long_options);
  22284.         }
  22285.  
  22286.         /*
  22287.          * Preserve backwards compatibility with callers that relied on
  22288.          * erroneous POSIX fix.
  22289.          */
  22290.         if ($version < 2) {
  22291.             if (isset($args[0]{0}) && $args[0]{0} != '-') {
  22292.                 array_shift($args);
  22293.             }
  22294.         }
  22295.  
  22296.         reset($args);
  22297.         while (list($i, $arg) = each($args)) {
  22298.  
  22299.             /* The special element '--' means explicit end of
  22300.                options. Treat the rest of the arguments as non-options
  22301.                and end the loop. */
  22302.             if ($arg == '--') {
  22303.                 $non_opts = array_merge($non_opts, array_slice($args, $i + 1));
  22304.                 break;
  22305.             }
  22306.  
  22307.             if ($arg{0} != '-' || (strlen($arg) > 1 && $arg{1} == '-' && !$long_options)) {
  22308.                 $non_opts = array_merge($non_opts, array_slice($args, $i));
  22309.                 break;
  22310.             } elseif (strlen($arg) > 1 && $arg{1} == '-') {
  22311.                 $error = Console_Getopt::_parseLongOption(substr($arg, 2), $long_options, $opts, $args);
  22312.                 if (PEAR::isError($error))
  22313.                     return $error;
  22314.             } elseif ($arg == '-') {
  22315.                 // - is stdin
  22316.                 $non_opts = array_merge($non_opts, array_slice($args, $i));
  22317.                 break;
  22318.             } else {
  22319.                 $error = Console_Getopt::_parseShortOption(substr($arg, 1), $short_options, $opts, $args);
  22320.                 if (PEAR::isError($error))
  22321.                     return $error;
  22322.             }
  22323.         }
  22324.  
  22325.         return array($opts, $non_opts);
  22326.     }
  22327.  
  22328.     /**
  22329.      * @access private
  22330.      *
  22331.      */
  22332.     function _parseShortOption($arg, $short_options, &$opts, &$args)
  22333.     {
  22334.         for ($i = 0; $i < strlen($arg); $i++) {
  22335.             $opt = $arg{$i};
  22336.             $opt_arg = null;
  22337.  
  22338.             /* Try to find the short option in the specifier string. */
  22339.             if (($spec = strstr($short_options, $opt)) === false || $arg{$i} == ':')
  22340.             {
  22341.                 return PEAR::raiseError("Console_Getopt: unrecognized option -- $opt");
  22342.             }
  22343.  
  22344.             if (strlen($spec) > 1 && $spec{1} == ':') {
  22345.                 if (strlen($spec) > 2 && $spec{2} == ':') {
  22346.                     if ($i + 1 < strlen($arg)) {
  22347.                         /* Option takes an optional argument. Use the remainder of
  22348.                            the arg string if there is anything left. */
  22349.                         $opts[] = array($opt, substr($arg, $i + 1));
  22350.                         break;
  22351.                     }
  22352.                 } else {
  22353.                     /* Option requires an argument. Use the remainder of the arg
  22354.                        string if there is anything left. */
  22355.                     if ($i + 1 < strlen($arg)) {
  22356.                         $opts[] = array($opt,  substr($arg, $i + 1));
  22357.                         break;
  22358.                     } else if (list(, $opt_arg) = each($args)) {
  22359.                         /* Else use the next argument. */;
  22360.                         if (Console_Getopt::_isShortOpt($opt_arg) || Console_Getopt::_isLongOpt($opt_arg)) {
  22361.                             return PEAR::raiseError("Console_Getopt: option requires an argument -- $opt");
  22362.                         }
  22363.                     } else {
  22364.                         return PEAR::raiseError("Console_Getopt: option requires an argument -- $opt");
  22365.                     }
  22366.                 }
  22367.             }
  22368.  
  22369.             $opts[] = array($opt, $opt_arg);
  22370.         }
  22371.     }
  22372.  
  22373.     /**
  22374.      * @access private
  22375.      *
  22376.      */
  22377.     function _isShortOpt($arg)
  22378.     {
  22379.         return strlen($arg) == 2 && $arg[0] == '-' && preg_match('/[a-zA-Z]/', $arg[1]);
  22380.     }
  22381.  
  22382.     /**
  22383.      * @access private
  22384.      *
  22385.      */
  22386.     function _isLongOpt($arg)
  22387.     {
  22388.         return strlen($arg) > 2 && $arg[0] == '-' && $arg[1] == '-' &&
  22389.             preg_match('/[a-zA-Z]+$/', substr($arg, 2));
  22390.     }
  22391.  
  22392.     /**
  22393.      * @access private
  22394.      *
  22395.      */
  22396.     function _parseLongOption($arg, $long_options, &$opts, &$args)
  22397.     {
  22398.         @list($opt, $opt_arg) = explode('=', $arg, 2);
  22399.         $opt_len = strlen($opt);
  22400.  
  22401.         for ($i = 0; $i < count($long_options); $i++) {
  22402.             $long_opt  = $long_options[$i];
  22403.             $opt_start = substr($long_opt, 0, $opt_len);
  22404.             $long_opt_name = str_replace('=', '', $long_opt);
  22405.  
  22406.             /* Option doesn't match. Go on to the next one. */
  22407.             if ($long_opt_name != $opt) {
  22408.                 continue;
  22409.             }
  22410.  
  22411.             $opt_rest  = substr($long_opt, $opt_len);
  22412.  
  22413.             /* Check that the options uniquely matches one of the allowed
  22414.                options. */
  22415.             if ($i + 1 < count($long_options)) {
  22416.                 $next_option_rest = substr($long_options[$i + 1], $opt_len);
  22417.             } else {
  22418.                 $next_option_rest = '';
  22419.             }
  22420.             if ($opt_rest != '' && $opt{0} != '=' &&
  22421.                 $i + 1 < count($long_options) &&
  22422.                 $opt == substr($long_options[$i+1], 0, $opt_len) &&
  22423.                 $next_option_rest != '' &&
  22424.                 $next_option_rest{0} != '=') {
  22425.                 return PEAR::raiseError("Console_Getopt: option --$opt is ambiguous");
  22426.             }
  22427.  
  22428.             if (substr($long_opt, -1) == '=') {
  22429.                 if (substr($long_opt, -2) != '==') {
  22430.                     /* Long option requires an argument.
  22431.                        Take the next argument if one wasn't specified. */;
  22432.                     if (!strlen($opt_arg) && !(list(, $opt_arg) = each($args))) {
  22433.                         return PEAR::raiseError("Console_Getopt: option --$opt requires an argument");
  22434.                     }
  22435.                     if (Console_Getopt::_isShortOpt($opt_arg) || Console_Getopt::_isLongOpt($opt_arg)) {
  22436.                         return PEAR::raiseError("Console_Getopt: option requires an argument --$opt");
  22437.                     }
  22438.                 }
  22439.             } else if ($opt_arg) {
  22440.                 return PEAR::raiseError("Console_Getopt: option --$opt doesn't allow an argument");
  22441.             }
  22442.  
  22443.             $opts[] = array('--' . $opt, $opt_arg);
  22444.             return;
  22445.         }
  22446.  
  22447.         return PEAR::raiseError("Console_Getopt: unrecognized option --$opt");
  22448.     }
  22449.  
  22450.     /**
  22451.     * Safely read the $argv PHP array across different PHP configurations.
  22452.     * Will take care on register_globals and register_argc_argv ini directives
  22453.     *
  22454.     * @access public
  22455.     * @return mixed the $argv PHP array or PEAR error if not registered
  22456.     */
  22457.     function readPHPArgv()
  22458.     {
  22459.         global $argv;
  22460.         if (!is_array($argv)) {
  22461.             if (!@is_array($_SERVER['argv'])) {
  22462.                 if (!@is_array($GLOBALS['HTTP_SERVER_VARS']['argv'])) {
  22463.                     return PEAR::raiseError("Console_Getopt: Could not read cmd args (register_argc_argv=Off?)");
  22464.                 }
  22465.                 return $GLOBALS['HTTP_SERVER_VARS']['argv'];
  22466.             }
  22467.             return $_SERVER['argv'];
  22468.         }
  22469.         return $argv;
  22470.     }
  22471.  
  22472. }
  22473.  
  22474. ?>
  22475. package.xml100644   1750   1750       75015 10755221545   6453 <?xml version="1.0" encoding="UTF-8"?>
  22476. <package packagerversion="1.7.0" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
  22477.  <name>PEAR</name>
  22478.  <channel>pear.php.net</channel>
  22479.  <summary>PEAR Base System</summary>
  22480.  <description>The PEAR package contains:
  22481.  * the PEAR installer, for creating, distributing
  22482.    and installing packages
  22483.  * the PEAR_Exception PHP5 error handling mechanism
  22484.  * the PEAR_ErrorStack advanced error handling mechanism
  22485.  * the PEAR_Error error handling mechanism
  22486.  * the OS_Guess class for retrieving info about the OS
  22487.    where PHP is running on
  22488.  * the System class for quick handling of common operations
  22489.    with files and directories
  22490.  * the PEAR base class
  22491.  
  22492.   Features in a nutshell:
  22493.   * full support for channels
  22494.   * pre-download dependency validation
  22495.   * new package.xml 2.0 format allows tremendous flexibility while maintaining BC
  22496.   * support for optional dependency groups and limited support for sub-packaging
  22497.   * robust dependency support
  22498.   * full dependency validation on uninstall
  22499.   * remote install for hosts with only ftp access - no more problems with
  22500.     restricted host installation
  22501.   * full support for mirroring
  22502.   * support for bundling several packages into a single tarball
  22503.   * support for static dependencies on a url-based package
  22504.   * support for custom file roles and installation tasks</description>
  22505.  <lead>
  22506.   <name>Greg Beaver</name>
  22507.   <user>cellog</user>
  22508.   <email>cellog@php.net</email>
  22509.   <active>yes</active>
  22510.  </lead>
  22511.  <lead>
  22512.   <name>Pierre-Alain Joye</name>
  22513.   <user>pajoye</user>
  22514.   <email>pierre@php.net</email>
  22515.   <active>no</active>
  22516.  </lead>
  22517.  <lead>
  22518.   <name>Stig Bakken</name>
  22519.   <user>ssb</user>
  22520.   <email>stig@php.net</email>
  22521.   <active>no</active>
  22522.  </lead>
  22523.  <lead>
  22524.   <name>Tomas V.V.Cox</name>
  22525.   <user>cox</user>
  22526.   <email>cox@idecnet.com</email>
  22527.   <active>no</active>
  22528.  </lead>
  22529.  <developer>
  22530.   <name>Helgi Thormar</name>
  22531.   <user>dufuz</user>
  22532.   <email>dufuz@php.net</email>
  22533.   <active>yes</active>
  22534.  </developer>
  22535.  <developer>
  22536.   <name>Tias Guns</name>
  22537.   <user>tias</user>
  22538.   <email>tias@php.net</email>
  22539.   <active>yes</active>
  22540.  </developer>
  22541.  <helper>
  22542.   <name>Tim Jackson</name>
  22543.   <user>timj</user>
  22544.   <email>timj@php.net</email>
  22545.   <active>no</active>
  22546.  </helper>
  22547.  <helper>
  22548.   <name>Bertrand Gugger</name>
  22549.   <user>toggg</user>
  22550.   <email>toggg@php.net</email>
  22551.   <active>no</active>
  22552.  </helper>
  22553.  <helper>
  22554.   <name>Martin Jansen</name>
  22555.   <user>mj</user>
  22556.   <email>mj@php.net</email>
  22557.   <active>no</active>
  22558.  </helper>
  22559.  <date>2008-02-14</date>
  22560.  <time>23:30:13</time>
  22561.  <version>
  22562.   <release>1.7.1</release>
  22563.   <api>1.7.0</api>
  22564.  </version>
  22565.  <stability>
  22566.   <release>stable</release>
  22567.   <api>stable</api>
  22568.  </stability>
  22569.  <license uri="http://www.php.net/license">PHP License</license>
  22570.  <notes>fixed since 1.7.0
  22571.  * fix bug #13030: Port not set for REST HTTP requests [timj]
  22572.  * fix bug #13029: Duplicate Host headers set when requesting REST data [timj]
  22573.  * fix bug #13047: PEAR fails to install *any* package [timj]
  22574.  
  22575. Known bugs to be fixed in version 1.7.2:
  22576.  - Bug #12945     PEAR_Registry::setConfig() does not set install path
  22577.  - Bug #12959     PEAR should give warning when doing "special" handling with cfg role
  22578.  - Bug #12960     role=cfg should automatically replace file if it has not been modified
  22579.  - Bug #13031     PEAR fails to authenticate when doing upgrade-all on non-default channel
  22580.  - Bug #13033     Signature to PEAR_REST_XX::listAll() changes between REST1.0 and 1.1</notes>
  22581.  <contents>
  22582.   <dir name="/">
  22583.    <file md5sum="fad1524a8ace078183017e6460501d3f" name="OS/Guess.php" role="php">
  22584.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22585.    </file>
  22586.    <file md5sum="a7a365eea26ab2693ff64ab8e8d84209" name="PEAR/ChannelFile/Parser.php" role="php">
  22587.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22588.    </file>
  22589.    <file md5sum="381496e0186e16d613ddb01564fca4a0" name="PEAR/Command/Auth.xml" role="php" />
  22590.    <file md5sum="8ad57c5c30e159f1819e42bdad92b76d" name="PEAR/Command/Auth.php" role="php">
  22591.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22592.    </file>
  22593.    <file md5sum="73602fd7f051eaf8d37452d0e3063bdb" name="PEAR/Command/Build.xml" role="php" />
  22594.    <file md5sum="9440451c1223e5f0beb4aa97cfe7972b" name="PEAR/Command/Build.php" role="php">
  22595.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22596.    </file>
  22597.    <file md5sum="5dfb7898501c43ab655c5f9b7176ea20" name="PEAR/Command/Channels.xml" role="php" />
  22598.    <file md5sum="657737df869a988f4ac0570af9ba8a16" name="PEAR/Command/Channels.php" role="php">
  22599.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22600.    </file>
  22601.    <file md5sum="2a5f9b7a2ce0f63f0cfd1ce280eb7e74" name="PEAR/Command/Common.php" role="php">
  22602.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22603.    </file>
  22604.    <file md5sum="91f189cb9423b5e87ee0abc5ea1a2be3" name="PEAR/Command/Config.xml" role="php" />
  22605.    <file md5sum="620e52d328cff1b1a4fcf6cc4b900604" name="PEAR/Command/Config.php" role="php">
  22606.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22607.    </file>
  22608.    <file md5sum="e0f361c6ebda100653e550a762a66a06" name="PEAR/Command/Install.xml" role="php" />
  22609.    <file md5sum="6a875280e052f974b1e602f46ca41e29" name="PEAR/Command/Install.php" role="php">
  22610.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22611.    </file>
  22612.    <file md5sum="5cb62a04c0a268f4edd64a49a3895c92" name="PEAR/Command/Mirror.xml" role="php" />
  22613.    <file md5sum="93913e680ee376751263399c09c2afc6" name="PEAR/Command/Mirror.php" role="php">
  22614.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22615.    </file>
  22616.    <file md5sum="bbf88f26cd10b1caa76d5eec474f093f" name="PEAR/Command/Package.xml" role="php" />
  22617.    <file md5sum="8c9a41328216db47ecf92ac6b0c63346" name="PEAR/Command/Package.php" role="php">
  22618.     <tasks:replace from="@DATA-DIR@" to="data_dir" type="pear-config" />
  22619.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22620.    </file>
  22621.    <file md5sum="29c0947f423695818f90759e65376e5c" name="PEAR/Command/Pickle.xml" role="php" />
  22622.    <file md5sum="25b3bd8485e8b71347b0426fb560bad1" name="PEAR/Command/Pickle.php" role="php">
  22623.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22624.    </file>
  22625.    <file md5sum="49b046cfc14747f0365e02e9c3f0e6dc" name="PEAR/Command/Registry.xml" role="php" />
  22626.    <file md5sum="e21b012325dcb5d5c9f30b0b885c989a" name="PEAR/Command/Registry.php" role="php">
  22627.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22628.    </file>
  22629.    <file md5sum="05729e322af29b0ddcdd85559e44cd41" name="PEAR/Command/Remote.xml" role="php" />
  22630.    <file md5sum="d081c690652b0c193994fc7369d8815a" name="PEAR/Command/Remote.php" role="php">
  22631.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22632.    </file>
  22633.    <file md5sum="118af6fbf9c37e90957f0bb9d5cf9d82" name="PEAR/Command/Test.xml" role="php" />
  22634.    <file md5sum="6bb986a5d83a63753753af0deabf72b2" name="PEAR/Command/Test.php" role="php">
  22635.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22636.    </file>
  22637.    <file md5sum="8cc9b7ce523ad54265883ca838d70437" name="PEAR/Downloader/Package.php" role="php">
  22638.     <tasks:replace from="@PEAR-VER@" to="version" type="package-info" />
  22639.    </file>
  22640.    <file md5sum="b37a0fe03b08cb40993046b16b1dd1e2" name="PEAR/Frontend/CLI.php" role="php">
  22641.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22642.    </file>
  22643.    <file md5sum="36850ec16ffcdfd014a21e742e8efd67" name="PEAR/Installer/Role/Common.php" role="php">
  22644.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22645.    </file>
  22646.    <file md5sum="d8c62e6275e3aaa7784290912406092c" name="PEAR/Installer/Role/Cfg.xml" role="php" />
  22647.    <file md5sum="fe3409813082cbc75bd4c4734914814d" name="PEAR/Installer/Role/Cfg.php" role="php">
  22648.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22649.    </file>
  22650.    <file md5sum="89a4a2a286e842d45a98974f40a0565c" name="PEAR/Installer/Role/Data.xml" role="php" />
  22651.    <file md5sum="79983acc4691ba254ca22d0707c9d73e" name="PEAR/Installer/Role/Data.php" role="php">
  22652.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22653.    </file>
  22654.    <file md5sum="b1ce0fe105251c3b75209d6518ee69ac" name="PEAR/Installer/Role/Doc.xml" role="php" />
  22655.    <file md5sum="4cda7f2935bfd2c9202269594f1b35f5" name="PEAR/Installer/Role/Doc.php" role="php">
  22656.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22657.    </file>
  22658.    <file md5sum="af71c0ad42d16a323afe24a4f884ef15" name="PEAR/Installer/Role/Ext.xml" role="php" />
  22659.    <file md5sum="705bb1516d78f7059658f4054d943147" name="PEAR/Installer/Role/Ext.php" role="php">
  22660.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22661.    </file>
  22662.    <file md5sum="ef88f0321d3e481c2130c95122cf76d8" name="PEAR/Installer/Role/Php.xml" role="php" />
  22663.    <file md5sum="383417bccb0ce4b225ec31f65c5cf984" name="PEAR/Installer/Role/Php.php" role="php">
  22664.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22665.    </file>
  22666.    <file md5sum="746461dc3b48af6d24094cb0211608f2" name="PEAR/Installer/Role/Script.xml" role="php" />
  22667.    <file md5sum="360bb22407134f106571dc71dbe55d69" name="PEAR/Installer/Role/Script.php" role="php">
  22668.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22669.    </file>
  22670.    <file md5sum="e147d63f168ea156fc2be38caaa63804" name="PEAR/Installer/Role/Src.xml" role="php" />
  22671.    <file md5sum="99a36f2406af7d785b636612acb1fe73" name="PEAR/Installer/Role/Src.php" role="php">
  22672.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22673.    </file>
  22674.    <file md5sum="a24b596ec987aa5688fc19e8ed4e97ea" name="PEAR/Installer/Role/Test.xml" role="php" />
  22675.    <file md5sum="9ca02df7f7619659cd04a9dbcbbefd1e" name="PEAR/Installer/Role/Test.php" role="php">
  22676.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22677.    </file>
  22678.    <file md5sum="7641e71c5785bb33a4261ebe25ed0fd7" name="PEAR/Installer/Role/Www.xml" role="php" />
  22679.    <file md5sum="31103803fd7d1114da74041523b56e44" name="PEAR/Installer/Role/Www.php" role="php">
  22680.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22681.    </file>
  22682.    <file md5sum="df9e37917e5eb2273bd170080187504b" name="PEAR/Installer/Role.php" role="php">
  22683.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22684.    </file>
  22685.    <file md5sum="e0d238adfc0cd119bf1c7391dc4d8e84" name="PEAR/PackageFile/Generator/v1.php" role="php">
  22686.     <tasks:replace from="@PEAR-VER@" to="version" type="package-info" />
  22687.    </file>
  22688.    <file md5sum="41fbeff9fa99070a131b55a246048747" name="PEAR/PackageFile/Generator/v2.php" role="php">
  22689.     <tasks:replace from="@PEAR-VER@" to="version" type="package-info" />
  22690.    </file>
  22691.    <file md5sum="e439d694e4e2c3b4146ee308a2758f5a" name="PEAR/PackageFile/Parser/v1.php" role="php">
  22692.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22693.    </file>
  22694.    <file md5sum="9fdba40240a1a72820780b5d6184391b" name="PEAR/PackageFile/Parser/v2.php" role="php">
  22695.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22696.    </file>
  22697.    <file md5sum="02a9ca28868ba5c86a212bad7bf8746b" name="PEAR/PackageFile/v2/rw.php" role="php">
  22698.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22699.    </file>
  22700.    <file md5sum="50ae0ae46204778eddb042c15b419758" name="PEAR/PackageFile/v2/Validator.php" role="php">
  22701.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22702.    </file>
  22703.    <file md5sum="f39f65088461a6de8e84f397357c46fe" name="PEAR/PackageFile/v1.php" role="php">
  22704.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22705.    </file>
  22706.    <file md5sum="12ecf6cd1bb212c378e44b9182d4aa35" name="PEAR/PackageFile/v2.php" role="php">
  22707.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22708.    </file>
  22709.    <file md5sum="f3c6f44136cdad1620c3b175f6879afc" name="PEAR/REST/10.php" role="php">
  22710.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22711.    </file>
  22712.    <file md5sum="11196c5909e6e547aa5062afe95f67a5" name="PEAR/REST/11.php" role="php">
  22713.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22714.    </file>
  22715.    <file md5sum="2335de1bf3d174b4fd6794986f109d7e" name="PEAR/REST/13.php" role="php">
  22716.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22717.    </file>
  22718.    <file md5sum="7c46da738c226c9020eb5e6708d1f864" name="PEAR/Task/Postinstallscript/rw.php" role="php">
  22719.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22720.    </file>
  22721.    <file md5sum="d04e4bb8e9dcd3d48a19cfa9389b136b" name="PEAR/Task/Replace/rw.php" role="php">
  22722.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22723.    </file>
  22724.    <file md5sum="7a6a8f12c7c8a6974a36fd9699d87640" name="PEAR/Task/Unixeol/rw.php" role="php">
  22725.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22726.    </file>
  22727.    <file md5sum="c836ac0c916325058fb5abeb3cb2e08b" name="PEAR/Task/Windowseol/rw.php" role="php">
  22728.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22729.    </file>
  22730.    <file md5sum="e16ad0cec65479de931d4bd759c86312" name="PEAR/Task/Common.php" role="php">
  22731.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22732.    </file>
  22733.    <file md5sum="92575321365952eb97cc6b13ce2d7ede" name="PEAR/Task/Postinstallscript.php" role="php">
  22734.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22735.    </file>
  22736.    <file md5sum="53e2f95d90b7d7fcb8c0d6f011554c56" name="PEAR/Task/Replace.php" role="php">
  22737.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22738.    </file>
  22739.    <file md5sum="d4c37e6109558386997b178850ee8402" name="PEAR/Task/Unixeol.php" role="php">
  22740.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22741.    </file>
  22742.    <file md5sum="836f0860f9ae37719d32267e0af6c934" name="PEAR/Task/Windowseol.php" role="php">
  22743.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22744.    </file>
  22745.    <file md5sum="4243bebc0d0d2b9ebec1c3c6cc95426f" name="PEAR/Validator/PECL.php" role="php">
  22746.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22747.    </file>
  22748.    <file md5sum="a9cf197907e5ea0b4ebdd2a48768561c" name="PEAR/Autoloader.php" role="php">
  22749.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22750.    </file>
  22751.    <file md5sum="b3a8f58c9d900545fcf44adb4babcaef" name="PEAR/Builder.php" role="php">
  22752.     <tasks:replace from="@PEAR-VER@" to="version" type="package-info" />
  22753.    </file>
  22754.    <file md5sum="afbc956590697d22b2485bac3ad51729" name="PEAR/ChannelFile.php" role="php">
  22755.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22756.    </file>
  22757.    <file md5sum="829abfe217c16a03099efe1c235846b1" name="PEAR/Command.php" role="php">
  22758.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22759.    </file>
  22760.    <file md5sum="0d46ebcdd475ee625e242e5f2cb6200c" name="PEAR/Common.php" role="php">
  22761.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22762.    </file>
  22763.    <file md5sum="ba24822f722e4175da4f1d4d23f85826" name="PEAR/Config.php" role="php">
  22764.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22765.    </file>
  22766.    <file md5sum="bcfff6330848fa83118e1ff11b3d7ba0" name="PEAR/Dependency.php" role="php" />
  22767.    <file md5sum="0488e80ccb2b392cd966d6ab4ba8b94b" name="PEAR/DependencyDB.php" role="php">
  22768.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22769.    </file>
  22770.    <file md5sum="30e0655dd5282eea478124f626337ac9" name="PEAR/Dependency2.php" role="php">
  22771.     <tasks:replace from="@PEAR-VER@" to="version" type="package-info" />
  22772.    </file>
  22773.    <file md5sum="f8aa205c6ef232bf383f478b30bdcbc5" name="PEAR/Downloader.php" role="php">
  22774.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22775.    </file>
  22776.    <file md5sum="6b34090416a2576a2f41134af21ce52c" name="PEAR/ErrorStack.php" role="php">
  22777.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22778.    </file>
  22779.    <file md5sum="342926ab74bb1688af12fe33679beeac" name="PEAR/Exception.php" role="php">
  22780.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22781.    </file>
  22782.    <file md5sum="e0e4cbcec4a972fbad779d0f9d323120" name="PEAR/FixPHP5PEARWarnings.php" role="php" />
  22783.    <file md5sum="cb4e237b180f6aca18f88e7b7db9a596" name="PEAR/Frontend.php" role="php">
  22784.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22785.    </file>
  22786.    <file md5sum="845eabb13099c31f87e83114bd5cc1c9" name="PEAR/Installer.php" role="php">
  22787.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22788.    </file>
  22789.    <file md5sum="455211423e10667a8b2e6d69cfc2c439" name="PEAR/PackageFile.php" role="php">
  22790.     <tasks:replace from="@PEAR-VER@" to="version" type="package-info" />
  22791.    </file>
  22792.    <file md5sum="05a6df11a07daf29a32d8c9ead6b0b5b" name="PEAR/Packager.php" role="php">
  22793.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22794.    </file>
  22795.    <file md5sum="e0574b876bd5b5bfff346a4fec43f2ff" name="PEAR/Registry.php" role="php">
  22796.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22797.    </file>
  22798.    <file md5sum="adab2d35578f95734a9f11db90804f9c" name="PEAR/Remote.php" role="php">
  22799.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22800.    </file>
  22801.    <file md5sum="3a8d179f6a7bb22d42d07ca38eb3d510" name="PEAR/REST.php" role="php">
  22802.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22803.    </file>
  22804.    <file md5sum="6f8b979b380e3acc504fd4b4fa9165de" name="PEAR/RunTest.php" role="php">
  22805.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22806.    </file>
  22807.    <file md5sum="7283eac0fed47c32ff03fde6c4950e71" name="PEAR/Validate.php" role="php">
  22808.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22809.    </file>
  22810.    <file md5sum="9d347c888482605e43bbe10879ede86c" name="PEAR/XMLParser.php" role="php">
  22811.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22812.    </file>
  22813.    <file baseinstalldir="/" md5sum="bd65b087b7707463525e9f0092337793" name="scripts/pear.bat" role="script">
  22814.     <tasks:replace from="@bin_dir@" to="bin_dir" type="pear-config" />
  22815.     <tasks:replace from="@php_bin@" to="php_bin" type="pear-config" />
  22816.     <tasks:replace from="@include_path@" to="php_dir" type="pear-config" />
  22817.     <tasks:windowseol />
  22818.    </file>
  22819.    <file baseinstalldir="/" md5sum="f92ee8acc4f00a7ca9ffedc1fe959b69" name="scripts/peardev.bat" role="script">
  22820.     <tasks:replace from="@bin_dir@" to="bin_dir" type="pear-config" />
  22821.     <tasks:replace from="@php_bin@" to="php_bin" type="pear-config" />
  22822.     <tasks:replace from="@include_path@" to="php_dir" type="pear-config" />
  22823.     <tasks:windowseol />
  22824.    </file>
  22825.    <file baseinstalldir="/" md5sum="34c1cb834dd1c03c9e40998b201d52e0" name="scripts/pecl.bat" role="script">
  22826.     <tasks:replace from="@bin_dir@" to="bin_dir" type="pear-config" />
  22827.     <tasks:replace from="@php_bin@" to="php_bin" type="pear-config" />
  22828.     <tasks:replace from="@include_path@" to="php_dir" type="pear-config" />
  22829.     <tasks:windowseol />
  22830.    </file>
  22831.    <file baseinstalldir="/" md5sum="5b495a3de3c6092bfbd93806937a0e4e" name="scripts/pear.sh" role="script">
  22832.     <tasks:replace from="@php_bin@" to="php_bin" type="pear-config" />
  22833.     <tasks:replace from="@php_dir@" to="php_dir" type="pear-config" />
  22834.     <tasks:replace from="@pear_version@" to="version" type="package-info" />
  22835.     <tasks:replace from="@include_path@" to="php_dir" type="pear-config" />
  22836.     <tasks:unixeol />
  22837.    </file>
  22838.    <file baseinstalldir="/" md5sum="c69b7eb6cf9198ef8f03a19dcb57ca42" name="scripts/peardev.sh" role="script">
  22839.     <tasks:replace from="@php_bin@" to="php_bin" type="pear-config" />
  22840.     <tasks:replace from="@php_dir@" to="php_dir" type="pear-config" />
  22841.     <tasks:replace from="@pear_version@" to="version" type="package-info" />
  22842.     <tasks:replace from="@include_path@" to="php_dir" type="pear-config" />
  22843.     <tasks:unixeol />
  22844.    </file>
  22845.    <file baseinstalldir="/" md5sum="d00c55f2aa48052c25db271e044e7551" name="scripts/pecl.sh" role="script">
  22846.     <tasks:replace from="@php_bin@" to="php_bin" type="pear-config" />
  22847.     <tasks:replace from="@php_dir@" to="php_dir" type="pear-config" />
  22848.     <tasks:replace from="@pear_version@" to="version" type="package-info" />
  22849.     <tasks:replace from="@include_path@" to="php_dir" type="pear-config" />
  22850.     <tasks:unixeol />
  22851.    </file>
  22852.    <file baseinstalldir="/" md5sum="07705150e7e98d6c85bcfa29f9ebfca0" name="scripts/pearcmd.php" role="php">
  22853.     <tasks:replace from="@php_bin@" to="php_bin" type="pear-config" />
  22854.     <tasks:replace from="@php_dir@" to="php_dir" type="pear-config" />
  22855.     <tasks:replace from="@pear_version@" to="version" type="package-info" />
  22856.     <tasks:replace from="@include_path@" to="php_dir" type="pear-config" />
  22857.    </file>
  22858.    <file baseinstalldir="/" md5sum="6356b5beefa80d0bbfd234d222873c7d" name="scripts/peclcmd.php" role="php">
  22859.     <tasks:replace from="@php_bin@" to="php_bin" type="pear-config" />
  22860.     <tasks:replace from="@php_dir@" to="php_dir" type="pear-config" />
  22861.     <tasks:replace from="@pear_version@" to="version" type="package-info" />
  22862.     <tasks:replace from="@include_path@" to="php_dir" type="pear-config" />
  22863.    </file>
  22864.    <file md5sum="671e6690634062ee521d2027a9971f22" name="INSTALL" role="doc" />
  22865.    <file md5sum="ca444da9174e05f8a0dc71d8ee47900f" name="package.dtd" role="data" />
  22866.    <file md5sum="d8b4207568c3c40570a01ef96be38182" name="PEAR.php" role="php">
  22867.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22868.    </file>
  22869.    <file md5sum="ae70dd96347165e048bd37521d6437f2" name="README" role="doc" />
  22870.    <file md5sum="a8a7405b1f0e4624c3e939bba7c084c9" name="System.php" role="php">
  22871.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  22872.    </file>
  22873.    <file md5sum="acd010e3bc43c0f72df584acde7b9158" name="template.spec" role="data" />
  22874.   </dir>
  22875.  </contents>
  22876.  <dependencies>
  22877.   <required>
  22878.    <php>
  22879.     <min>4.3.0</min>
  22880.    </php>
  22881.    <pearinstaller>
  22882.     <min>1.4.3</min>
  22883.    </pearinstaller>
  22884.    <package>
  22885.     <name>Archive_Tar</name>
  22886.     <channel>pear.php.net</channel>
  22887.     <min>1.1</min>
  22888.     <recommended>1.3.2</recommended>
  22889.     <exclude>1.3.0</exclude>
  22890.    </package>
  22891.    <package>
  22892.     <name>Structures_Graph</name>
  22893.     <channel>pear.php.net</channel>
  22894.     <min>1.0.2</min>
  22895.     <recommended>1.0.2</recommended>
  22896.    </package>
  22897.    <package>
  22898.     <name>Console_Getopt</name>
  22899.     <channel>pear.php.net</channel>
  22900.     <min>1.2</min>
  22901.     <recommended>1.2.3</recommended>
  22902.    </package>
  22903.    <package>
  22904.     <name>PEAR_Frontend_Web</name>
  22905.     <channel>pear.php.net</channel>
  22906.     <max>0.4</max>
  22907.     <conflicts />
  22908.    </package>
  22909.    <package>
  22910.     <name>PEAR_Frontend_Gtk</name>
  22911.     <channel>pear.php.net</channel>
  22912.     <max>0.4.0</max>
  22913.     <exclude>0.4.0</exclude>
  22914.     <conflicts />
  22915.    </package>
  22916.    <extension>
  22917.     <name>xml</name>
  22918.    </extension>
  22919.    <extension>
  22920.     <name>pcre</name>
  22921.    </extension>
  22922.   </required>
  22923.   <optional>
  22924.    <package>
  22925.     <name>XML_RPC</name>
  22926.     <channel>pear.php.net</channel>
  22927.     <min>1.4.0</min>
  22928.    </package>
  22929.   </optional>
  22930.   <group hint="PEAR's web-based installer" name="webinstaller">
  22931.    <package>
  22932.     <name>PEAR_Frontend_Web</name>
  22933.     <channel>pear.php.net</channel>
  22934.     <min>0.5.1</min>
  22935.    </package>
  22936.   </group>
  22937.   <group hint="PEAR's PHP-GTK-based installer" name="gtkinstaller">
  22938.    <package>
  22939.     <name>PEAR_Frontend_Gtk</name>
  22940.     <channel>pear.php.net</channel>
  22941.     <min>0.4.0</min>
  22942.    </package>
  22943.   </group>
  22944.   <group hint="PEAR's PHP-GTK2-based installer" name="gtk2installer">
  22945.    <package>
  22946.     <name>PEAR_Frontend_Gtk2</name>
  22947.     <channel>pear.php.net</channel>
  22948.    </package>
  22949.   </group>
  22950.  </dependencies>
  22951.  <phprelease>
  22952.   <installconditions>
  22953.    <os>
  22954.     <name>windows</name>
  22955.    </os>
  22956.   </installconditions>
  22957.   <filelist>
  22958.    <install as="pear.bat" name="scripts/pear.bat" />
  22959.    <install as="peardev.bat" name="scripts/peardev.bat" />
  22960.    <install as="pecl.bat" name="scripts/pecl.bat" />
  22961.    <install as="pearcmd.php" name="scripts/pearcmd.php" />
  22962.    <install as="peclcmd.php" name="scripts/peclcmd.php" />
  22963.    <ignore name="scripts/peardev.sh" />
  22964.    <ignore name="scripts/pear.sh" />
  22965.    <ignore name="scripts/pecl.sh" />
  22966.   </filelist>
  22967.  </phprelease>
  22968.  <phprelease>
  22969.   <filelist>
  22970.    <install as="pear" name="scripts/pear.sh" />
  22971.    <install as="peardev" name="scripts/peardev.sh" />
  22972.    <install as="pecl" name="scripts/pecl.sh" />
  22973.    <install as="pearcmd.php" name="scripts/pearcmd.php" />
  22974.    <install as="peclcmd.php" name="scripts/peclcmd.php" />
  22975.    <ignore name="scripts/pear.bat" />
  22976.    <ignore name="scripts/peardev.bat" />
  22977.    <ignore name="scripts/pecl.bat" />
  22978.   </filelist>
  22979.  </phprelease>
  22980.  <changelog>
  22981.   <release>
  22982.    <version>
  22983.     <release>1.6.2</release>
  22984.     <api>1.6.0</api>
  22985.    </version>
  22986.    <stability>
  22987.     <release>stable</release>
  22988.     <api>stable</api>
  22989.    </stability>
  22990.    <date>2007-09-09</date>
  22991.    <license uri="http://www.php.net/license">PHP License</license>
  22992.    <notes>Minor bugfix release
  22993. * fix Bug #11420: warning on pecl (un)install with --register-only option [cellog]
  22994. * fix Bug #11481: PEAR_PackageFile_Parser_v1 skips single-char directories [pmjones]
  22995. * fix Bug #11517: Error : download directory "/var/cache/php-pear"
  22996.   is not writeable. [remicollet]
  22997. * fix Bug #11616: Incorrect equality operator used when comparing md5 check sums [robham]
  22998. * fix Bug #11642: PEAR fails to authenticate when downloading deps from non-default
  22999.   channels [timj]
  23000. * fix Bug #11657: Installer generate bad "dirtree" using INSTALL_ROOT [remicollet]
  23001. * fix Bug #11678: Registry.php getChannel() deadlocks [cellog]
  23002. * fix Bug #11703: pear convert and package.xml with optional dependencies fails [cellog]
  23003. * fix Bug #11754: Error at upgrade-all command run [cellog]
  23004. * fix Bug #11861: uninstall of package did not delete directory created during install
  23005.   of package [cellog]
  23006. * fix Bug #11862: Notice: Array to string conversion in PEAR/PackageFile.php on line 433
  23007.   [cellog]
  23008. * fix Bug #11883: run-tests -u -p SomePackage should run the topmost
  23009.   "AllTests.php" file [cellog]
  23010. * fix Bug #11936: run-tests fails to preserve SYSTEMROOT environment variable [cellog]</notes>
  23011.   </release>
  23012.   <release>
  23013.    <version>
  23014.     <release>1.7.0RC1</release>
  23015.     <api>1.6.0</api>
  23016.    </version>
  23017.    <stability>
  23018.     <release>beta</release>
  23019.     <api>stable</api>
  23020.    </stability>
  23021.    <date>2007-12-10</date>
  23022.    <license uri="http://www.php.net/license">PHP License</license>
  23023.    <notes>* fix Bug #12116: Accept-Encoding not supported: breaks installer [jldupont]
  23024. * fix Bug #12162: config-create doesn't work after installing custom roles [cellog]
  23025. * fix Bug #12553: System::find() does not find exact filename matches [cellog/jorrit]
  23026. * fix Bug #12554: enableExtension() zeros php.ini in some instances [jlightsey]
  23027. * implement Request #11964: introduce www role, www_dir config variable [cellog]
  23028. * implement Request #12108: Add "config" (cfg) role [cellog]
  23029. * implement Request #12147: Avoid compile-time strict warnings [cellog]</notes>
  23030.   </release>
  23031.   <release>
  23032.    <version>
  23033.     <release>1.7.0RC2</release>
  23034.     <api>1.6.0</api>
  23035.    </version>
  23036.    <stability>
  23037.     <release>beta</release>
  23038.     <api>stable</api>
  23039.    </stability>
  23040.    <date>2007-01-03</date>
  23041.    <license uri="http://www.php.net/license">PHP License</license>
  23042.    <notes>**WARNING** MAJOR BC BREAK IN WWW ROLE**
  23043. The www role was installing into packagename/ and now installs into the root directory
  23044. of www_dir.  This is necessary to allow easy migration from applications already using
  23045. Role_Web
  23046.  
  23047.  fixed since 1.7.0RC1:
  23048. * fix Bug #12662: System::_parseArgs() should be declared statically [cellog]
  23049. * fix Bug #12661: System::mktemp needs to be declaired statically [cellog]
  23050. * implement PEAR_Error::__toString() as alias to getMessage() [cellog]
  23051.  fixed since 1.6.2:
  23052. * fix Bug #12116: Accept-Encoding not supported: breaks installer [jldupont]
  23053. * fix Bug #12162: config-create doesn't work after installing custom roles [cellog]
  23054. * fix Bug #12553: System::find() does not find exact filename matches [cellog/jorrit]
  23055. * fix Bug #12554: enableExtension() zeros php.ini in some instances [jlightsey]
  23056. * implement Request #11964: introduce www role, www_dir config variable [cellog]
  23057. * implement Request #12108: Add "config" (cfg) role [cellog]
  23058. * implement Request #12147: Avoid compile-time strict warnings [cellog]</notes>
  23059.   </release>
  23060.   <release>
  23061.    <version>
  23062.     <release>1.7.0</release>
  23063.     <api>1.7.0</api>
  23064.    </version>
  23065.    <stability>
  23066.     <release>stable</release>
  23067.     <api>stable</api>
  23068.    </stability>
  23069.    <date>2008-01-31</date>
  23070.    <license uri="http://www.php.net/license">PHP License</license>
  23071.    <notes>Minor feature addition release
  23072.  
  23073. Known bugs to be fixed in version 1.7.1:
  23074.  - Bug #12945     PEAR_Registry::setConfig() does not set install path
  23075.  - Bug #12959     PEAR should give warning when doing "special" handling with cfg role
  23076.  - Bug #12960     role=cfg should automatically replace file if it has not been modified
  23077.  - Bug #13031     PEAR fails to authenticate when doing upgrade-all on non-default channel
  23078.  - Bug #13033     Signature to PEAR_REST_XX::listAll() changes between REST1.0 and 1.1
  23079.  
  23080. fixed since 1.7.0RC2
  23081.  * fix bug #13030: Port not set for REST HTTP requests [timj]
  23082.  * fix bug #13029: Duplicate Host headers set when requesting REST data [timj]
  23083.  * fix Bug #12987: improper calls to class_exists [weirdan]
  23084.  * fix Bug #12954: Host header missing when using proxy [flint]
  23085.  * fix Bug #12918: file tasks ignored for role=src [cellog]
  23086.  * fix Bug #12816: <configureoption> default isn't being parsed [jon]
  23087.  * fix Bug #12793: run-tests fails when using --ARGS-- in phpt test files [izi]
  23088. fixed since 1.7.0RC1:
  23089.  * fix Bug #12818: package.xml 1.0 parsing can drop lines [cellog]
  23090.  * fix Bug #12662: System::_parseArgs() should be declared statically [cellog]
  23091.  * fix Bug #12661: System::mktemp needs to be declaired statically [cellog]
  23092.  * implement PEAR_Error::__toString() as alias to getMessage() [cellog]
  23093. fixed since 1.6.2:
  23094.  * fix Bug #12116: Accept-Encoding not supported: breaks installer [jldupont]
  23095.  * fix Bug #12162: config-create doesn't work after installing custom roles [cellog]
  23096.  * fix Bug #12553: System::find() does not find exact filename matches [cellog/jorrit]
  23097.  * fix Bug #12554: enableExtension() zeros php.ini in some instances [jlightsey]
  23098.  * implement Request #11964: introduce www role, www_dir config variable [cellog]
  23099.  * implement Request #12108: Add "config" (cfg) role [cellog]
  23100.  * implement Request #12147: Avoid compile-time strict warnings [cellog]</notes>
  23101.   </release>
  23102.  </changelog>
  23103. </package>
  23104. PEAR-1.7.1/OS/Guess.php100644   1750   1750       25470 10755221545   7647 <?php
  23105. /**
  23106.  * The OS_Guess class
  23107.  *
  23108.  * PHP versions 4 and 5
  23109.  *
  23110.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  23111.  * that is available through the world-wide-web at the following URI:
  23112.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  23113.  * the PHP License and are unable to obtain it through the web, please
  23114.  * send a note to license@php.net so we can mail you a copy immediately.
  23115.  *
  23116.  * @category   pear
  23117.  * @package    PEAR
  23118.  * @author     Stig Bakken <ssb@php.net>
  23119.  * @author     Gregory Beaver <cellog@php.net>
  23120.  * @copyright  1997-2008 The PHP Group
  23121.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  23122.  * @version    CVS: $Id: Guess.php,v 1.26 2008/01/03 20:26:34 cellog Exp $
  23123.  * @link       http://pear.php.net/package/PEAR
  23124.  * @since      File available since PEAR 0.1
  23125.  */
  23126.  
  23127. // {{{ uname examples
  23128.  
  23129. // php_uname() without args returns the same as 'uname -a', or a PHP-custom
  23130. // string for Windows.
  23131. // PHP versions prior to 4.3 return the uname of the host where PHP was built,
  23132. // as of 4.3 it returns the uname of the host running the PHP code.
  23133. //
  23134. // PC RedHat Linux 7.1:
  23135. // Linux host.example.com 2.4.2-2 #1 Sun Apr 8 20:41:30 EDT 2001 i686 unknown
  23136. //
  23137. // PC Debian Potato:
  23138. // Linux host 2.4.17 #2 SMP Tue Feb 12 15:10:04 CET 2002 i686 unknown
  23139. //
  23140. // PC FreeBSD 3.3:
  23141. // FreeBSD host.example.com 3.3-STABLE FreeBSD 3.3-STABLE #0: Mon Feb 21 00:42:31 CET 2000     root@example.com:/usr/src/sys/compile/CONFIG  i386
  23142. //
  23143. // PC FreeBSD 4.3:
  23144. // FreeBSD host.example.com 4.3-RELEASE FreeBSD 4.3-RELEASE #1: Mon Jun 25 11:19:43 EDT 2001     root@example.com:/usr/src/sys/compile/CONFIG  i386
  23145. //
  23146. // PC FreeBSD 4.5:
  23147. // FreeBSD host.example.com 4.5-STABLE FreeBSD 4.5-STABLE #0: Wed Feb  6 23:59:23 CET 2002     root@example.com:/usr/src/sys/compile/CONFIG  i386
  23148. //
  23149. // PC FreeBSD 4.5 w/uname from GNU shellutils:
  23150. // FreeBSD host.example.com 4.5-STABLE FreeBSD 4.5-STABLE #0: Wed Feb  i386 unknown
  23151. //
  23152. // HP 9000/712 HP-UX 10:
  23153. // HP-UX iq B.10.10 A 9000/712 2008429113 two-user license
  23154. //
  23155. // HP 9000/712 HP-UX 10 w/uname from GNU shellutils:
  23156. // HP-UX host B.10.10 A 9000/712 unknown
  23157. //
  23158. // IBM RS6000/550 AIX 4.3:
  23159. // AIX host 3 4 000003531C00
  23160. //
  23161. // AIX 4.3 w/uname from GNU shellutils:
  23162. // AIX host 3 4 000003531C00 unknown
  23163. //
  23164. // SGI Onyx IRIX 6.5 w/uname from GNU shellutils:
  23165. // IRIX64 host 6.5 01091820 IP19 mips
  23166. //
  23167. // SGI Onyx IRIX 6.5:
  23168. // IRIX64 host 6.5 01091820 IP19
  23169. //
  23170. // SparcStation 20 Solaris 8 w/uname from GNU shellutils:
  23171. // SunOS host.example.com 5.8 Generic_108528-12 sun4m sparc
  23172. //
  23173. // SparcStation 20 Solaris 8:
  23174. // SunOS host.example.com 5.8 Generic_108528-12 sun4m sparc SUNW,SPARCstation-20
  23175. //
  23176. // Mac OS X (Darwin)
  23177. // Darwin home-eden.local 7.5.0 Darwin Kernel Version 7.5.0: Thu Aug  5 19:26:16 PDT 2004; root:xnu/xnu-517.7.21.obj~3/RELEASE_PPC  Power Macintosh
  23178. //
  23179. // Mac OS X early versions
  23180. // 
  23181.  
  23182. // }}}
  23183.  
  23184. /* TODO:
  23185.  * - define endianness, to allow matchSignature("bigend") etc.
  23186.  */
  23187.  
  23188. /**
  23189.  * Retrieves information about the current operating system
  23190.  *
  23191.  * This class uses php_uname() to grok information about the current OS
  23192.  *
  23193.  * @category   pear
  23194.  * @package    PEAR
  23195.  * @author     Stig Bakken <ssb@php.net>
  23196.  * @author     Gregory Beaver <cellog@php.net>
  23197.  * @copyright  1997-2008 The PHP Group
  23198.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  23199.  * @version    Release: 1.7.1
  23200.  * @link       http://pear.php.net/package/PEAR
  23201.  * @since      Class available since Release 0.1
  23202.  */
  23203. class OS_Guess
  23204. {
  23205.     var $sysname;
  23206.     var $nodename;
  23207.     var $cpu;
  23208.     var $release;
  23209.     var $extra;
  23210.  
  23211.     function OS_Guess($uname = null)
  23212.     {
  23213.         list($this->sysname,
  23214.              $this->release,
  23215.              $this->cpu,
  23216.              $this->extra,
  23217.              $this->nodename) = $this->parseSignature($uname);
  23218.     }
  23219.  
  23220.     function parseSignature($uname = null)
  23221.     {
  23222.         static $sysmap = array(
  23223.             'HP-UX' => 'hpux',
  23224.             'IRIX64' => 'irix',
  23225.         );
  23226.         static $cpumap = array(
  23227.             'i586' => 'i386',
  23228.             'i686' => 'i386',
  23229.             'ppc' => 'powerpc',
  23230.         );
  23231.         if ($uname === null) {
  23232.             $uname = php_uname();
  23233.         }
  23234.         $parts = split('[[:space:]]+', trim($uname));
  23235.         $n = count($parts);
  23236.  
  23237.         $release = $machine = $cpu = '';
  23238.         $sysname = $parts[0];
  23239.         $nodename = $parts[1];
  23240.         $cpu = $parts[$n-1];
  23241.         $extra = '';
  23242.         if ($cpu == 'unknown') {
  23243.             $cpu = $parts[$n-2];
  23244.         }
  23245.  
  23246.         switch ($sysname) {
  23247.             case 'AIX' :
  23248.                 $release = "$parts[3].$parts[2]";
  23249.                 break;
  23250.             case 'Windows' :
  23251.                 switch ($parts[1]) {
  23252.                     case '95/98':
  23253.                         $release = '9x';
  23254.                         break;
  23255.                     default:
  23256.                         $release = $parts[1];
  23257.                         break;
  23258.                 }
  23259.                 $cpu = 'i386';
  23260.                 break;
  23261.             case 'Linux' :
  23262.                 $extra = $this->_detectGlibcVersion();
  23263.                 // use only the first two digits from the kernel version
  23264.                 $release = ereg_replace('^([[:digit:]]+\.[[:digit:]]+).*', '\1', $parts[2]);
  23265.                 break;
  23266.             case 'Mac' :
  23267.                 $sysname = 'darwin';
  23268.                 $nodename = $parts[2];
  23269.                 $release = $parts[3];
  23270.                 if ($cpu == 'Macintosh') {
  23271.                     if ($parts[$n - 2] == 'Power') {
  23272.                         $cpu = 'powerpc';
  23273.                     }
  23274.                 }
  23275.                 break;
  23276.             case 'Darwin' :
  23277.                 if ($cpu == 'Macintosh') {
  23278.                     if ($parts[$n - 2] == 'Power') {
  23279.                         $cpu = 'powerpc';
  23280.                     }
  23281.                 }
  23282.                 $release = ereg_replace('^([[:digit:]]+\.[[:digit:]]+).*', '\1', $parts[2]);
  23283.                 break;
  23284.             default:
  23285.                 $release = ereg_replace('-.*', '', $parts[2]);
  23286.                 break;
  23287.         }
  23288.  
  23289.  
  23290.         if (isset($sysmap[$sysname])) {
  23291.             $sysname = $sysmap[$sysname];
  23292.         } else {
  23293.             $sysname = strtolower($sysname);
  23294.         }
  23295.         if (isset($cpumap[$cpu])) {
  23296.             $cpu = $cpumap[$cpu];
  23297.         }
  23298.         return array($sysname, $release, $cpu, $extra, $nodename);
  23299.     }
  23300.  
  23301.     function _detectGlibcVersion()
  23302.     {
  23303.         static $glibc = false;
  23304.         if ($glibc !== false) {
  23305.             return $glibc; // no need to run this multiple times
  23306.         }
  23307.         $major = $minor = 0;
  23308.         include_once "System.php";
  23309.         // Use glibc's <features.h> header file to
  23310.         // get major and minor version number:
  23311.         if (@file_exists('/usr/include/features.h') &&
  23312.               @is_readable('/usr/include/features.h')) {
  23313.             if (!@file_exists('/usr/bin/cpp') || !@is_executable('/usr/bin/cpp')) {
  23314.                 $features_file = fopen('/usr/include/features.h', 'rb');
  23315.                 while (!feof($features_file)) {
  23316.                     $line = fgets($features_file, 8192);
  23317.                     if (!$line || (strpos($line, '#define') === false)) {
  23318.                         continue;
  23319.                     }
  23320.                     if (strpos($line, '__GLIBC__')) {
  23321.                         // major version number #define __GLIBC__ version
  23322.                         $line = preg_split('/\s+/', $line);
  23323.                         $glibc_major = trim($line[2]);
  23324.                         if (isset($glibc_minor)) {
  23325.                             break;
  23326.                         }
  23327.                         continue;
  23328.                     }
  23329.                     if (strpos($line, '__GLIBC_MINOR__'))  {
  23330.                         // got the minor version number
  23331.                         // #define __GLIBC_MINOR__ version
  23332.                         $line = preg_split('/\s+/', $line);
  23333.                         $glibc_minor = trim($line[2]);
  23334.                         if (isset($glibc_major)) {
  23335.                             break;
  23336.                         }
  23337.                         continue;
  23338.                     }
  23339.                 }
  23340.                 fclose($features_file);
  23341.                 if (!isset($glibc_major) || !isset($glibc_minor)) {
  23342.                     return $glibc = '';
  23343.                 }
  23344.                 return $glibc = 'glibc' . trim($glibc_major) . "." . trim($glibc_minor) ;
  23345.             } // no cpp
  23346.             $tmpfile = System::mktemp("glibctest");
  23347.             $fp = fopen($tmpfile, "w");
  23348.             fwrite($fp, "#include <features.h>\n__GLIBC__ __GLIBC_MINOR__\n");
  23349.             fclose($fp);
  23350.             $cpp = popen("/usr/bin/cpp $tmpfile", "r");
  23351.             while ($line = fgets($cpp, 1024)) {
  23352.                 if ($line{0} == '#' || trim($line) == '') {
  23353.                     continue;
  23354.                 }
  23355.                 if (list($major, $minor) = explode(' ', trim($line))) {
  23356.                     break;
  23357.                 }
  23358.             }
  23359.             pclose($cpp);
  23360.             unlink($tmpfile);
  23361.         } // features.h
  23362.         if (!($major && $minor) && @is_link('/lib/libc.so.6')) {
  23363.             // Let's try reading the libc.so.6 symlink
  23364.             if (ereg('^libc-(.*)\.so$', basename(readlink('/lib/libc.so.6')), $matches)) {
  23365.                 list($major, $minor) = explode('.', $matches[1]);
  23366.             }
  23367.         }
  23368.         if (!($major && $minor)) {
  23369.             return $glibc = '';
  23370.         }
  23371.         return $glibc = "glibc{$major}.{$minor}";
  23372.     }
  23373.  
  23374.     function getSignature()
  23375.     {
  23376.         if (empty($this->extra)) {
  23377.             return "{$this->sysname}-{$this->release}-{$this->cpu}";
  23378.         }
  23379.         return "{$this->sysname}-{$this->release}-{$this->cpu}-{$this->extra}";
  23380.     }
  23381.  
  23382.     function getSysname()
  23383.     {
  23384.         return $this->sysname;
  23385.     }
  23386.  
  23387.     function getNodename()
  23388.     {
  23389.         return $this->nodename;
  23390.     }
  23391.  
  23392.     function getCpu()
  23393.     {
  23394.         return $this->cpu;
  23395.     }
  23396.  
  23397.     function getRelease()
  23398.     {
  23399.         return $this->release;
  23400.     }
  23401.  
  23402.     function getExtra()
  23403.     {
  23404.         return $this->extra;
  23405.     }
  23406.  
  23407.     function matchSignature($match)
  23408.     {
  23409.         if (is_array($match)) {
  23410.             $fragments = $match;
  23411.         } else {
  23412.             $fragments = explode('-', $match);
  23413.         }
  23414.         $n = count($fragments);
  23415.         $matches = 0;
  23416.         if ($n > 0) {
  23417.             $matches += $this->_matchFragment($fragments[0], $this->sysname);
  23418.         }
  23419.         if ($n > 1) {
  23420.             $matches += $this->_matchFragment($fragments[1], $this->release);
  23421.         }
  23422.         if ($n > 2) {
  23423.             $matches += $this->_matchFragment($fragments[2], $this->cpu);
  23424.         }
  23425.         if ($n > 3) {
  23426.             $matches += $this->_matchFragment($fragments[3], $this->extra);
  23427.         }
  23428.         return ($matches == $n);
  23429.     }
  23430.  
  23431.     function _matchFragment($fragment, $value)
  23432.     {
  23433.         if (strcspn($fragment, '*?') < strlen($fragment)) {
  23434.             $reg = '^' . str_replace(array('*', '?', '/'), array('.*', '.', '\\/'), $fragment) . '$';
  23435.             return eregi($reg, $value);
  23436.         }
  23437.         return ($fragment == '*' || !strcasecmp($fragment, $value));
  23438.     }
  23439.  
  23440. }
  23441. /*
  23442.  * Local Variables:
  23443.  * indent-tabs-mode: nil
  23444.  * c-basic-offset: 4
  23445.  * End:
  23446.  */
  23447. ?>
  23448. PEAR-1.7.1/PEAR/ChannelFile/Parser.php100644   1750   1750        4120 10755221545  12340 <?php
  23449. /**
  23450.  * PEAR_ChannelFile_Parser for parsing channel.xml
  23451.  *
  23452.  * PHP versions 4 and 5
  23453.  *
  23454.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  23455.  * that is available through the world-wide-web at the following URI:
  23456.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  23457.  * the PHP License and are unable to obtain it through the web, please
  23458.  * send a note to license@php.net so we can mail you a copy immediately.
  23459.  *
  23460.  * @category   pear
  23461.  * @package    PEAR
  23462.  * @author     Greg Beaver <cellog@php.net>
  23463.  * @copyright  1997-2008 The PHP Group
  23464.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  23465.  * @version    CVS: $Id: Parser.php,v 1.5 2008/01/03 20:26:36 cellog Exp $
  23466.  * @link       http://pear.php.net/package/PEAR
  23467.  * @since      File available since Release 1.4.0a1
  23468.  */
  23469.  
  23470. /**
  23471.  * base xml parser class
  23472.  */
  23473. require_once 'PEAR/XMLParser.php';
  23474. require_once 'PEAR/ChannelFile.php';
  23475. /**
  23476.  * Parser for channel.xml
  23477.  * @category   pear
  23478.  * @package    PEAR
  23479.  * @author     Greg Beaver <cellog@php.net>
  23480.  * @copyright  1997-2008 The PHP Group
  23481.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  23482.  * @version    Release: 1.7.1
  23483.  * @link       http://pear.php.net/package/PEAR
  23484.  * @since      Class available since Release 1.4.0a1
  23485.  */
  23486. class PEAR_ChannelFile_Parser extends PEAR_XMLParser
  23487. {
  23488.     var $_config;
  23489.     var $_logger;
  23490.     var $_registry;
  23491.  
  23492.     function setConfig(&$c)
  23493.     {
  23494.         $this->_config = &$c;
  23495.         $this->_registry = &$c->getRegistry();
  23496.     }
  23497.  
  23498.     function setLogger(&$l)
  23499.     {
  23500.         $this->_logger = &$l;
  23501.     }
  23502.  
  23503.     function parse($data, $file)
  23504.     {
  23505.         if (PEAR::isError($err = parent::parse($data, $file))) {
  23506.             return $err;
  23507.         }
  23508.         $ret = new PEAR_ChannelFile;
  23509.         $ret->setConfig($this->_config);
  23510.         if (isset($this->_logger)) {
  23511.             $ret->setLogger($this->_logger);
  23512.         }
  23513.         $ret->fromArray($this->_unserializedData);
  23514.         // make sure the filelist is in the easy to read format needed
  23515.         $ret->flattenFilelist();
  23516.         $ret->setPackagefile($file, $archive);
  23517.         return $ret;
  23518.     }
  23519. }
  23520. ?>PEAR-1.7.1/PEAR/Command/Auth.xml100644   1750   1750        1756 10755221545  11240 <commands version="1.0">
  23521.  <login>
  23522.   <summary>Connects and authenticates to remote server</summary>
  23523.   <shortcut>li</shortcut>
  23524.   <function>doLogin</function>
  23525.   <options />
  23526.   <doc><channel name>
  23527. Log in to a remote channel server.  <channel name> is not supplied, 
  23528. the default channel is used. To use remote functions in the installer
  23529. that require any kind of privileges, you need to log in first.  The
  23530. username and password you enter here will be stored in your per-user
  23531. PEAR configuration (~/.pearrc on Unix-like systems).  After logging
  23532. in, your username and password will be sent along in subsequent
  23533. operations on the remote server.</doc>
  23534.  </login>
  23535.  <logout>
  23536.   <summary>Logs out from the remote server</summary>
  23537.   <shortcut>lo</shortcut>
  23538.   <function>doLogout</function>
  23539.   <options />
  23540.   <doc>
  23541. Logs out from the remote server.  This command does not actually
  23542. connect to the remote server, it only deletes the stored username and
  23543. password from your user configuration.</doc>
  23544.  </logout>
  23545. </commands>PEAR-1.7.1/PEAR/Command/Auth.php100644   1750   1750       14202 10755221545  11235 <?php
  23546. /**
  23547.  * PEAR_Command_Auth (login, logout commands)
  23548.  *
  23549.  * PHP versions 4 and 5
  23550.  *
  23551.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  23552.  * that is available through the world-wide-web at the following URI:
  23553.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  23554.  * the PHP License and are unable to obtain it through the web, please
  23555.  * send a note to license@php.net so we can mail you a copy immediately.
  23556.  *
  23557.  * @category   pear
  23558.  * @package    PEAR
  23559.  * @author     Stig Bakken <ssb@php.net>
  23560.  * @author     Greg Beaver <cellog@php.net>
  23561.  * @copyright  1997-2008 The PHP Group
  23562.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  23563.  * @version    CVS: $Id: Auth.php,v 1.31 2008/01/03 20:26:36 cellog Exp $
  23564.  * @link       http://pear.php.net/package/PEAR
  23565.  * @since      File available since Release 0.1
  23566.  */
  23567.  
  23568. /**
  23569.  * base class
  23570.  */
  23571. require_once 'PEAR/Command/Common.php';
  23572. require_once 'PEAR/Config.php';
  23573.  
  23574. /**
  23575.  * PEAR commands for login/logout
  23576.  *
  23577.  * @category   pear
  23578.  * @package    PEAR
  23579.  * @author     Stig Bakken <ssb@php.net>
  23580.  * @author     Greg Beaver <cellog@php.net>
  23581.  * @copyright  1997-2008 The PHP Group
  23582.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  23583.  * @version    Release: 1.7.1
  23584.  * @link       http://pear.php.net/package/PEAR
  23585.  * @since      Class available since Release 0.1
  23586.  */
  23587. class PEAR_Command_Auth extends PEAR_Command_Common
  23588. {
  23589.     // {{{ properties
  23590.  
  23591.     var $commands = array(
  23592.         'login' => array(
  23593.             'summary' => 'Connects and authenticates to remote server',
  23594.             'shortcut' => 'li',
  23595.             'function' => 'doLogin',
  23596.             'options' => array(),
  23597.             'doc' => '<channel name>
  23598. Log in to a remote channel server.  If <channel name> is not supplied, 
  23599. the default channel is used. To use remote functions in the installer
  23600. that require any kind of privileges, you need to log in first.  The
  23601. username and password you enter here will be stored in your per-user
  23602. PEAR configuration (~/.pearrc on Unix-like systems).  After logging
  23603. in, your username and password will be sent along in subsequent
  23604. operations on the remote server.',
  23605.             ),
  23606.         'logout' => array(
  23607.             'summary' => 'Logs out from the remote server',
  23608.             'shortcut' => 'lo',
  23609.             'function' => 'doLogout',
  23610.             'options' => array(),
  23611.             'doc' => '
  23612. Logs out from the remote server.  This command does not actually
  23613. connect to the remote server, it only deletes the stored username and
  23614. password from your user configuration.',
  23615.             )
  23616.  
  23617.         );
  23618.  
  23619.     // }}}
  23620.  
  23621.     // {{{ constructor
  23622.  
  23623.     /**
  23624.      * PEAR_Command_Auth constructor.
  23625.      *
  23626.      * @access public
  23627.      */
  23628.     function PEAR_Command_Auth(&$ui, &$config)
  23629.     {
  23630.         parent::PEAR_Command_Common($ui, $config);
  23631.     }
  23632.  
  23633.     // }}}
  23634.  
  23635.     // {{{ doLogin()
  23636.  
  23637.     /**
  23638.      * Execute the 'login' command.
  23639.      *
  23640.      * @param string $command command name
  23641.      *
  23642.      * @param array $options option_name => value
  23643.      *
  23644.      * @param array $params list of additional parameters
  23645.      *
  23646.      * @return bool TRUE on success or
  23647.      * a PEAR error on failure
  23648.      *
  23649.      * @access public
  23650.      */
  23651.     function doLogin($command, $options, $params)
  23652.     {
  23653.         $reg = &$this->config->getRegistry();
  23654.         
  23655.         // If a parameter is supplied, use that as the channel to log in to
  23656.         if (isset($params[0])) {
  23657.             $channel = $params[0];
  23658.         } else {
  23659.             $channel = $this->config->get('default_channel');
  23660.         }
  23661.         
  23662.         $chan = $reg->getChannel($channel);
  23663.         if (PEAR::isError($chan)) {
  23664.             return $this->raiseError($chan);
  23665.         }
  23666.         $server = $this->config->get('preferred_mirror', null, $channel);
  23667.         $remote = &$this->config->getRemote();
  23668.         $username = $this->config->get('username', null, $channel);
  23669.         if (empty($username)) {
  23670.             $username = isset($_ENV['USER']) ? $_ENV['USER'] : null;
  23671.         }
  23672.         $this->ui->outputData("Logging in to $server.", $command);
  23673.         
  23674.         list($username, $password) = $this->ui->userDialog(
  23675.             $command,
  23676.             array('Username', 'Password'),
  23677.             array('text',     'password'),
  23678.             array($username,  '')
  23679.             );
  23680.         $username = trim($username);
  23681.         $password = trim($password);
  23682.  
  23683.         $ourfile = $this->config->getConfFile('user');
  23684.         if (!$ourfile) {
  23685.             $ourfile = $this->config->getConfFile('system');
  23686.         }
  23687.  
  23688.         $this->config->set('username', $username, 'user', $channel);
  23689.         $this->config->set('password', $password, 'user', $channel);
  23690.  
  23691.         if ($chan->supportsREST()) {
  23692.             $ok = true;
  23693.         } else {
  23694.             $remote->expectError(401);
  23695.             $ok = $remote->call('logintest');
  23696.             $remote->popExpect();
  23697.         }
  23698.         if ($ok === true) {
  23699.             $this->ui->outputData("Logged in.", $command);
  23700.             // avoid changing any temporary settings changed with -d
  23701.             $ourconfig = new PEAR_Config($ourfile, $ourfile);
  23702.             $ourconfig->set('username', $username, 'user', $channel);
  23703.             $ourconfig->set('password', $password, 'user', $channel);
  23704.             $ourconfig->store();
  23705.         } else {
  23706.             return $this->raiseError("Login failed!");
  23707.         }
  23708.         return true;
  23709.     }
  23710.  
  23711.     // }}}
  23712.     // {{{ doLogout()
  23713.  
  23714.     /**
  23715.      * Execute the 'logout' command.
  23716.      *
  23717.      * @param string $command command name
  23718.      *
  23719.      * @param array $options option_name => value
  23720.      *
  23721.      * @param array $params list of additional parameters
  23722.      *
  23723.      * @return bool TRUE on success or
  23724.      * a PEAR error on failure
  23725.      *
  23726.      * @access public
  23727.      */
  23728.     function doLogout($command, $options, $params)
  23729.     {
  23730.         $reg = &$this->config->getRegistry();
  23731.         $channel = $this->config->get('default_channel');
  23732.         $chan = $reg->getChannel($channel);
  23733.         if (PEAR::isError($chan)) {
  23734.             return $this->raiseError($chan);
  23735.         }
  23736.         $server = $this->config->get('preferred_mirror');
  23737.         $this->ui->outputData("Logging out from $server.", $command);
  23738.         $this->config->remove('username');
  23739.         $this->config->remove('password');
  23740.         $this->config->store();
  23741.         return true;
  23742.     }
  23743.  
  23744.     // }}}
  23745. }
  23746.  
  23747. ?>PEAR-1.7.1/PEAR/Command/Build.xml100644   1750   1750         404 10755221545  11343 <commands version="1.0">
  23748.  <build>
  23749.   <summary>Build an Extension From C Source</summary>
  23750.   <function>doBuild</function>
  23751.   <shortcut>b</shortcut>
  23752.   <options />
  23753.   <doc>[package.xml]
  23754. Builds one or more extensions contained in a package.</doc>
  23755.  </build>
  23756. </commands>PEAR-1.7.1/PEAR/Command/Build.php100644   1750   1750        5430 10755221545  11356 <?php
  23757. /**
  23758.  * PEAR_Command_Auth (build command)
  23759.  *
  23760.  * PHP versions 4 and 5
  23761.  *
  23762.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  23763.  * that is available through the world-wide-web at the following URI:
  23764.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  23765.  * the PHP License and are unable to obtain it through the web, please
  23766.  * send a note to license@php.net so we can mail you a copy immediately.
  23767.  *
  23768.  * @category   pear
  23769.  * @package    PEAR
  23770.  * @author     Stig Bakken <ssb@php.net>
  23771.  * @author     Tomas V.V.Cox <cox@idecnet.com>
  23772.  * @author     Greg Beaver <cellog@php.net>
  23773.  * @copyright  1997-2008 The PHP Group
  23774.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  23775.  * @version    CVS: $Id: Build.php,v 1.14 2008/01/03 20:26:36 cellog Exp $
  23776.  * @link       http://pear.php.net/package/PEAR
  23777.  * @since      File available since Release 0.1
  23778.  */
  23779.  
  23780. /**
  23781.  * base class
  23782.  */
  23783. require_once 'PEAR/Command/Common.php';
  23784.  
  23785. /**
  23786.  * PEAR commands for building extensions.
  23787.  *
  23788.  * @category   pear
  23789.  * @package    PEAR
  23790.  * @author     Stig Bakken <ssb@php.net>
  23791.  * @author     Tomas V.V.Cox <cox@idecnet.com>
  23792.  * @author     Greg Beaver <cellog@php.net>
  23793.  * @copyright  1997-2008 The PHP Group
  23794.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  23795.  * @version    Release: 1.7.1
  23796.  * @link       http://pear.php.net/package/PEAR
  23797.  * @since      Class available since Release 0.1
  23798.  */
  23799. class PEAR_Command_Build extends PEAR_Command_Common
  23800. {
  23801.     // {{{ properties
  23802.  
  23803.     var $commands = array(
  23804.         'build' => array(
  23805.             'summary' => 'Build an Extension From C Source',
  23806.             'function' => 'doBuild',
  23807.             'shortcut' => 'b',
  23808.             'options' => array(),
  23809.             'doc' => '[package.xml]
  23810. Builds one or more extensions contained in a package.'
  23811.             ),
  23812.         );
  23813.  
  23814.     // }}}
  23815.  
  23816.     // {{{ constructor
  23817.  
  23818.     /**
  23819.      * PEAR_Command_Build constructor.
  23820.      *
  23821.      * @access public
  23822.      */
  23823.     function PEAR_Command_Build(&$ui, &$config)
  23824.     {
  23825.         parent::PEAR_Command_Common($ui, $config);
  23826.     }
  23827.  
  23828.     // }}}
  23829.  
  23830.     // {{{ doBuild()
  23831.  
  23832.     function doBuild($command, $options, $params)
  23833.     {
  23834.         require_once 'PEAR/Builder.php';
  23835.         if (sizeof($params) < 1) {
  23836.             $params[0] = 'package.xml';
  23837.         }
  23838.         $builder = &new PEAR_Builder($this->ui);
  23839.         $this->debug = $this->config->get('verbose');
  23840.         $err = $builder->build($params[0], array(&$this, 'buildCallback'));
  23841.         if (PEAR::isError($err)) {
  23842.             return $err;
  23843.         }
  23844.         return true;
  23845.     }
  23846.  
  23847.     // }}}
  23848.     // {{{ buildCallback()
  23849.  
  23850.     function buildCallback($what, $data)
  23851.     {
  23852.         if (($what == 'cmdoutput' && $this->debug > 1) ||
  23853.             ($what == 'output' && $this->debug > 0)) {
  23854.             $this->ui->outputData(rtrim($data), 'build');
  23855.         }
  23856.     }
  23857.  
  23858.     // }}}
  23859. }
  23860. PEAR-1.7.1/PEAR/Command/Channels.xml100644   1750   1750        6030 10755221545  12060 <commands version="1.0">
  23861.  <list-channels>
  23862.   <summary>List Available Channels</summary>
  23863.   <function>doList</function>
  23864.   <shortcut>lc</shortcut>
  23865.   <options />
  23866.   <doc>
  23867. List all available channels for installation.
  23868. </doc>
  23869.  </list-channels>
  23870.  <update-channels>
  23871.   <summary>Update the Channel List</summary>
  23872.   <function>doUpdateAll</function>
  23873.   <shortcut>uc</shortcut>
  23874.   <options />
  23875.   <doc>
  23876. List all installed packages in all channels.
  23877. </doc>
  23878.  </update-channels>
  23879.  <channel-delete>
  23880.   <summary>Remove a Channel From the List</summary>
  23881.   <function>doDelete</function>
  23882.   <shortcut>cde</shortcut>
  23883.   <options />
  23884.   <doc><channel name>
  23885. Delete a channel from the registry.  You may not
  23886. remove any channel that has installed packages.
  23887. </doc>
  23888.  </channel-delete>
  23889.  <channel-add>
  23890.   <summary>Add a Channel</summary>
  23891.   <function>doAdd</function>
  23892.   <shortcut>ca</shortcut>
  23893.   <options />
  23894.   <doc><channel.xml>
  23895. Add a private channel to the channel list.  Note that all
  23896. public channels should be synced using "update-channels".
  23897. Parameter may be either a local file or remote URL to a
  23898. channel.xml.
  23899. </doc>
  23900.  </channel-add>
  23901.  <channel-update>
  23902.   <summary>Update an Existing Channel</summary>
  23903.   <function>doUpdate</function>
  23904.   <shortcut>cu</shortcut>
  23905.   <options>
  23906.    <force>
  23907.     <shortopt>f</shortopt>
  23908.     <doc>will force download of new channel.xml if an existing channel name is used</doc>
  23909.    </force>
  23910.    <channel>
  23911.     <shortopt>c</shortopt>
  23912.     <arg>CHANNEL</arg>
  23913.     <doc>will force download of new channel.xml if an existing channel name is used</doc>
  23914.    </channel>
  23915.   </options>
  23916.   <doc>[<channel.xml>|<channel name>]
  23917. Update a channel in the channel list directly.  Note that all
  23918. public channels can be synced using "update-channels".
  23919. Parameter may be a local or remote channel.xml, or the name of
  23920. an existing channel.
  23921. </doc>
  23922.  </channel-update>
  23923.  <channel-info>
  23924.   <summary>Retrieve Information on a Channel</summary>
  23925.   <function>doInfo</function>
  23926.   <shortcut>ci</shortcut>
  23927.   <options />
  23928.   <doc><package>
  23929. List the files in an installed package.
  23930. </doc>
  23931.  </channel-info>
  23932.  <channel-alias>
  23933.   <summary>Specify an alias to a channel name</summary>
  23934.   <function>doAlias</function>
  23935.   <shortcut>cha</shortcut>
  23936.   <options />
  23937.   <doc><channel> <alias>
  23938. Specify a specific alias to use for a channel name.
  23939. The alias may not be an existing channel name or
  23940. alias.
  23941. </doc>
  23942.  </channel-alias>
  23943.  <channel-discover>
  23944.   <summary>Initialize a Channel from its server</summary>
  23945.   <function>doDiscover</function>
  23946.   <shortcut>di</shortcut>
  23947.   <options />
  23948.   <doc>[<channel.xml>|<channel name>]
  23949. Initialize a channel from its server and create a local channel.xml.
  23950. If <channel name> is in the format "<username>:<password>@<channel>" then
  23951. <username> and <password> will be set as the login username/password for
  23952. <channel>. Use caution when passing the username/password in this way, as
  23953. it may allow other users on your computer to briefly view your username/
  23954. password via the system's process list.
  23955. </doc>
  23956.  </channel-discover>
  23957. </commands>
  23958. PEAR-1.7.1/PEAR/Command/Channels.php100644   1750   1750       73163 10755221545  12102 <?php
  23959. // /* vim: set expandtab tabstop=4 shiftwidth=4: */
  23960. /**
  23961.  * PEAR_Command_Channels (list-channels, update-channels, channel-delete, channel-add,
  23962.  * channel-update, channel-info, channel-alias, channel-discover commands)
  23963.  *
  23964.  * PHP versions 4 and 5
  23965.  *
  23966.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  23967.  * that is available through the world-wide-web at the following URI:
  23968.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  23969.  * the PHP License and are unable to obtain it through the web, please
  23970.  * send a note to license@php.net so we can mail you a copy immediately.
  23971.  *
  23972.  * @category   pear
  23973.  * @package    PEAR
  23974.  * @author     Stig Bakken <ssb@php.net>
  23975.  * @author     Greg Beaver <cellog@php.net>
  23976.  * @copyright  1997-2008 The PHP Group
  23977.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  23978.  * @version    CVS: $Id: Channels.php,v 1.57 2008/01/03 20:26:36 cellog Exp $
  23979.  * @link       http://pear.php.net/package/PEAR
  23980.  * @since      File available since Release 1.4.0a1
  23981.  */
  23982.  
  23983. /**
  23984.  * base class
  23985.  */
  23986. require_once 'PEAR/Command/Common.php';
  23987.  
  23988. /**
  23989.  * PEAR commands for managing channels.
  23990.  *
  23991.  * @category   pear
  23992.  * @package    PEAR
  23993.  * @author     Greg Beaver <cellog@php.net>
  23994.  * @copyright  1997-2008 The PHP Group
  23995.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  23996.  * @version    Release: 1.7.1
  23997.  * @link       http://pear.php.net/package/PEAR
  23998.  * @since      Class available since Release 1.4.0a1
  23999.  */
  24000. class PEAR_Command_Channels extends PEAR_Command_Common
  24001. {
  24002.     // {{{ properties
  24003.  
  24004.     var $commands = array(
  24005.         'list-channels' => array(
  24006.             'summary' => 'List Available Channels',
  24007.             'function' => 'doList',
  24008.             'shortcut' => 'lc',
  24009.             'options' => array(),
  24010.             'doc' => '
  24011. List all available channels for installation.
  24012. ',
  24013.             ),
  24014.         'update-channels' => array(
  24015.             'summary' => 'Update the Channel List',
  24016.             'function' => 'doUpdateAll',
  24017.             'shortcut' => 'uc',
  24018.             'options' => array(),
  24019.             'doc' => '
  24020. List all installed packages in all channels.
  24021. '
  24022.             ),
  24023.         'channel-delete' => array(
  24024.             'summary' => 'Remove a Channel From the List',
  24025.             'function' => 'doDelete',
  24026.             'shortcut' => 'cde',
  24027.             'options' => array(),
  24028.             'doc' => '<channel name>
  24029. Delete a channel from the registry.  You may not
  24030. remove any channel that has installed packages.
  24031. '
  24032.             ),
  24033.         'channel-add' => array(
  24034.             'summary' => 'Add a Channel',
  24035.             'function' => 'doAdd',
  24036.             'shortcut' => 'ca',
  24037.             'options' => array(),
  24038.             'doc' => '<channel.xml>
  24039. Add a private channel to the channel list.  Note that all
  24040. public channels should be synced using "update-channels".
  24041. Parameter may be either a local file or remote URL to a
  24042. channel.xml.
  24043. '
  24044.             ),
  24045.         'channel-update' => array(
  24046.             'summary' => 'Update an Existing Channel',
  24047.             'function' => 'doUpdate',
  24048.             'shortcut' => 'cu',
  24049.             'options' => array(
  24050.                 'force' => array(
  24051.                     'shortopt' => 'f',
  24052.                     'doc' => 'will force download of new channel.xml if an existing channel name is used',
  24053.                     ),
  24054.                 'channel' => array(
  24055.                     'shortopt' => 'c',
  24056.                     'arg' => 'CHANNEL',
  24057.                     'doc' => 'will force download of new channel.xml if an existing channel name is used',
  24058.                     ),
  24059. ),
  24060.             'doc' => '[<channel.xml>|<channel name>]
  24061. Update a channel in the channel list directly.  Note that all
  24062. public channels can be synced using "update-channels".
  24063. Parameter may be a local or remote channel.xml, or the name of
  24064. an existing channel.
  24065. '
  24066.             ),
  24067.         'channel-info' => array(
  24068.             'summary' => 'Retrieve Information on a Channel',
  24069.             'function' => 'doInfo',
  24070.             'shortcut' => 'ci',
  24071.             'options' => array(),
  24072.             'doc' => '<package>
  24073. List the files in an installed package.
  24074. '
  24075.             ),
  24076.         'channel-alias' => array(
  24077.             'summary' => 'Specify an alias to a channel name',
  24078.             'function' => 'doAlias',
  24079.             'shortcut' => 'cha',
  24080.             'options' => array(),
  24081.             'doc' => '<channel> <alias>
  24082. Specify a specific alias to use for a channel name.
  24083. The alias may not be an existing channel name or
  24084. alias.
  24085. '
  24086.             ),
  24087.         'channel-discover' => array(
  24088.             'summary' => 'Initialize a Channel from its server',
  24089.             'function' => 'doDiscover',
  24090.             'shortcut' => 'di',
  24091.             'options' => array(),
  24092.             'doc' => '[<channel.xml>|<channel name>]
  24093. Initialize a channel from its server and create a local channel.xml.
  24094. If <channel name> is in the format "<username>:<password>@<channel>" then
  24095. <username> and <password> will be set as the login username/password for
  24096. <channel>. Use caution when passing the username/password in this way, as
  24097. it may allow other users on your computer to briefly view your username/
  24098. password via the system\'s process list.
  24099. '
  24100.             ),
  24101.         );
  24102.  
  24103.     // }}}
  24104.     // {{{ constructor
  24105.  
  24106.     /**
  24107.      * PEAR_Command_Registry constructor.
  24108.      *
  24109.      * @access public
  24110.      */
  24111.     function PEAR_Command_Channels(&$ui, &$config)
  24112.     {
  24113.         parent::PEAR_Command_Common($ui, $config);
  24114.     }
  24115.  
  24116.     // }}}
  24117.  
  24118.     // {{{ doList()
  24119.     
  24120.     function _sortChannels($a, $b)
  24121.     {
  24122.         return strnatcasecmp($a->getName(), $b->getName());
  24123.     }
  24124.  
  24125.     function doList($command, $options, $params)
  24126.     {
  24127.         $reg = &$this->config->getRegistry();
  24128.         $registered = $reg->getChannels();
  24129.         usort($registered, array(&$this, '_sortchannels'));
  24130.         $i = $j = 0;
  24131.         $data = array(
  24132.             'caption' => 'Registered Channels:',
  24133.             'border' => true,
  24134.             'headline' => array('Channel', 'Summary')
  24135.             );
  24136.         foreach ($registered as $channel) {
  24137.             $data['data'][] = array($channel->getName(),
  24138.                                       $channel->getSummary());
  24139.         }
  24140.         if (count($registered)==0) {
  24141.             $data = '(no registered channels)';
  24142.         }
  24143.         $this->ui->outputData($data, $command);
  24144.         return true;
  24145.     }
  24146.     
  24147.     function doUpdateAll($command, $options, $params)
  24148.     {
  24149.         $reg = &$this->config->getRegistry();
  24150.         $channels = $reg->getChannels();
  24151.  
  24152.         $success = true;
  24153.         foreach ($channels as $channel) {
  24154.             if ($channel->getName() != '__uri') {
  24155.                 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  24156.                 $err = $this->doUpdate('channel-update',
  24157.                                           $options,
  24158.                                           array($channel->getName()));
  24159.                 if (PEAR::isError($err)) {
  24160.                     $this->ui->outputData($err->getMessage(), $command);
  24161.                     $success = false;
  24162.                 } else {
  24163.                     $success &= $err;
  24164.                 }
  24165.             }
  24166.         }
  24167.         return $success;
  24168.     }
  24169.     
  24170.     function doInfo($command, $options, $params)
  24171.     {
  24172.         if (sizeof($params) != 1) {
  24173.             return $this->raiseError("No channel specified");
  24174.         }
  24175.         $reg = &$this->config->getRegistry();
  24176.         $channel = strtolower($params[0]);
  24177.         if ($reg->channelExists($channel)) {
  24178.             $chan = $reg->getChannel($channel);
  24179.             if (PEAR::isError($chan)) {
  24180.                 return $this->raiseError($chan);
  24181.             }
  24182.         } else {
  24183.             if (strpos($channel, '://')) {
  24184.                 $downloader = &$this->getDownloader();
  24185.                 $tmpdir = $this->config->get('temp_dir');
  24186.                 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  24187.                 $loc = $downloader->downloadHttp($channel, $this->ui, $tmpdir);
  24188.                 PEAR::staticPopErrorHandling();
  24189.                 if (PEAR::isError($loc)) {
  24190.                     return $this->raiseError('Cannot open "' . $channel .
  24191.                         '" (' . $loc->getMessage() . ')');
  24192.                 } else {
  24193.                     $contents = implode('', file($loc));
  24194.                 }
  24195.             } else {
  24196.                 if (file_exists($params[0])) {
  24197.                     $fp = fopen($params[0], 'r');
  24198.                     if (!$fp) {
  24199.                         return $this->raiseError('Cannot open "' . $params[0] . '"');
  24200.                     }
  24201.                 } else {
  24202.                     return $this->raiseError('Unknown channel "' . $channel . '"');
  24203.                 }
  24204.                 $contents = '';
  24205.                 while (!feof($fp)) {
  24206.                     $contents .= fread($fp, 1024);
  24207.                 }
  24208.                 fclose($fp);
  24209.             }
  24210.             if (!class_exists('PEAR_ChannelFile')) {
  24211.                 require_once 'PEAR/ChannelFile.php';
  24212.             }
  24213.             $chan = new PEAR_ChannelFile;
  24214.             $chan->fromXmlString($contents);
  24215.             $chan->validate();
  24216.             if ($errs = $chan->getErrors(true)) {
  24217.                 foreach ($errs as $err) {
  24218.                     $this->ui->outputData($err['level'] . ': ' . $err['message']);
  24219.                 }
  24220.                 return $this->raiseError('Channel file "' . $params[0] . '" is not valid');
  24221.             }
  24222.         }
  24223.         if ($chan) {
  24224.             $channel = $chan->getName();
  24225.             $caption = 'Channel ' . $channel . ' Information:';
  24226.             $data1 = array(
  24227.                 'caption' => $caption,
  24228.                 'border' => true);
  24229.             $data1['data']['server'] = array('Name and Server', $chan->getName());
  24230.             if ($chan->getAlias() != $chan->getName()) {
  24231.                 $data1['data']['alias'] = array('Alias', $chan->getAlias());
  24232.             }
  24233.             $data1['data']['summary'] = array('Summary', $chan->getSummary());
  24234.             $validate = $chan->getValidationPackage();
  24235.             $data1['data']['vpackage'] = array('Validation Package Name', $validate['_content']);
  24236.             $data1['data']['vpackageversion'] =
  24237.                 array('Validation Package Version', $validate['attribs']['version']);
  24238.             $d = array();
  24239.             $d['main'] = $data1;
  24240.  
  24241.             $data['data'] = array();
  24242.             $data['caption'] = 'Server Capabilities';
  24243.             $data['headline'] = array('Type', 'Version/REST type', 'Function Name/REST base');
  24244.             $capabilities = $chan->getFunctions('xmlrpc');
  24245.             $soaps = $chan->getFunctions('soap');
  24246.             if ($capabilities || $soaps || $chan->supportsREST()) {
  24247.                 if ($capabilities) {
  24248.                     if (!isset($capabilities[0])) {
  24249.                         $capabilities = array($capabilities);
  24250.                     }
  24251.                     foreach ($capabilities as $protocol) {
  24252.                         $data['data'][] = array('xmlrpc', $protocol['attribs']['version'],
  24253.                             $protocol['_content']);
  24254.                     }
  24255.                 }
  24256.                 if ($soaps) {
  24257.                     if (!isset($soaps[0])) {
  24258.                         $soaps = array($soaps);
  24259.                     }
  24260.                     foreach ($soaps as $protocol) {
  24261.                         $data['data'][] = array('soap', $protocol['attribs']['version'],
  24262.                             $protocol['_content']);
  24263.                     }
  24264.                 }
  24265.                 if ($chan->supportsREST()) {
  24266.                     $funcs = $chan->getFunctions('rest');
  24267.                     if (!isset($funcs[0])) {
  24268.                         $funcs = array($funcs);
  24269.                     }
  24270.                     foreach ($funcs as $protocol) {
  24271.                         $data['data'][] = array('rest', $protocol['attribs']['type'],
  24272.                             $protocol['_content']); 
  24273.                     }
  24274.                 }
  24275.             } else {
  24276.                 $data['data'][] = array('No supported protocols');
  24277.             }
  24278.             $d['protocols'] = $data;
  24279.             $data['data'] = array();
  24280.             $mirrors = $chan->getMirrors();
  24281.             if ($mirrors) {
  24282.                 $data['caption'] = 'Channel ' . $channel . ' Mirrors:';
  24283.                 unset($data['headline']);
  24284.                 foreach ($mirrors as $mirror) {
  24285.                     $data['data'][] = array($mirror['attribs']['host']);
  24286.                     $d['mirrors'] = $data;
  24287.                 }
  24288.                 foreach ($mirrors as $i => $mirror) {
  24289.                     $data['data'] = array();
  24290.                     $data['caption'] = 'Mirror ' . $mirror['attribs']['host'] . ' Capabilities';
  24291.                     $data['headline'] = array('Type', 'Version/REST type', 'Function Name/REST base');
  24292.                     $capabilities = $chan->getFunctions('xmlrpc', $mirror['attribs']['host']);
  24293.                     $soaps = $chan->getFunctions('soap', $mirror['attribs']['host']);
  24294.                     if ($capabilities || $soaps || $chan->supportsREST($mirror['attribs']['host'])) {
  24295.                         if ($capabilities) {
  24296.                             if (!isset($capabilities[0])) {
  24297.                                 $capabilities = array($capabilities);
  24298.                             }
  24299.                             foreach ($capabilities as $protocol) {
  24300.                                 $data['data'][] = array('xmlrpc', $protocol['attribs']['version'],
  24301.                                     $protocol['_content']);
  24302.                             }
  24303.                         }
  24304.                         if ($soaps) {
  24305.                             if (!isset($soaps[0])) {
  24306.                                 $soaps = array($soaps);
  24307.                             }
  24308.                             foreach ($soaps as $protocol) {
  24309.                                 $data['data'][] = array('soap', $protocol['attribs']['version'],
  24310.                                     $protocol['_content']);
  24311.                             }
  24312.                         }
  24313.                         if ($chan->supportsREST($mirror['attribs']['host'])) {
  24314.                             $funcs = $chan->getFunctions('rest', $mirror['attribs']['host']);
  24315.                             if (!isset($funcs[0])) {
  24316.                                 $funcs = array($funcs);
  24317.                             }
  24318.                             foreach ($funcs as $protocol) {
  24319.                                 $data['data'][] = array('rest', $protocol['attribs']['type'],
  24320.                                     $protocol['_content']); 
  24321.                             }
  24322.                         }
  24323.                     } else {
  24324.                         $data['data'][] = array('No supported protocols');
  24325.                     }
  24326.                     $d['mirrorprotocols' . $i] = $data;
  24327.                 }
  24328.             }
  24329.             $this->ui->outputData($d, 'channel-info');
  24330.         } else {
  24331.             return $this->raiseError('Serious error: Channel "' . $params[0] .
  24332.                 '" has a corrupted registry entry');
  24333.         }
  24334.     }
  24335.  
  24336.     // }}}
  24337.     
  24338.     function doDelete($command, $options, $params)
  24339.     {
  24340.         if (sizeof($params) != 1) {
  24341.             return $this->raiseError('channel-delete: no channel specified');
  24342.         }
  24343.         $reg = &$this->config->getRegistry();
  24344.         if (!$reg->channelExists($params[0])) {
  24345.             return $this->raiseError('channel-delete: channel "' . $params[0] . '" does not exist');
  24346.         }
  24347.         $channel = $reg->channelName($params[0]);
  24348.         if ($channel == 'pear.php.net') {
  24349.             return $this->raiseError('Cannot delete the pear.php.net channel');
  24350.         }
  24351.         if ($channel == 'pecl.php.net') {
  24352.             return $this->raiseError('Cannot delete the pecl.php.net channel');
  24353.         }
  24354.         if ($channel == '__uri') {
  24355.             return $this->raiseError('Cannot delete the __uri pseudo-channel');
  24356.         }
  24357.         if (PEAR::isError($err = $reg->listPackages($channel))) {
  24358.             return $err;
  24359.         }
  24360.         if (count($err)) {
  24361.             return $this->raiseError('Channel "' . $channel .
  24362.                 '" has installed packages, cannot delete');
  24363.         }
  24364.         if (!$reg->deleteChannel($channel)) {
  24365.             return $this->raiseError('Channel "' . $channel . '" deletion failed');
  24366.         } else {
  24367.             $this->config->deleteChannel($channel);
  24368.             $this->ui->outputData('Channel "' . $channel . '" deleted', $command);
  24369.         }
  24370.     }
  24371.  
  24372.     function doAdd($command, $options, $params)
  24373.     {
  24374.         if (sizeof($params) != 1) {
  24375.             return $this->raiseError('channel-add: no channel file specified');
  24376.         }
  24377.         if (strpos($params[0], '://')) {
  24378.             $downloader = &$this->getDownloader();
  24379.             $tmpdir = $this->config->get('temp_dir');
  24380.             if (!file_exists($tmpdir)) {
  24381.                 require_once 'System.php';
  24382.                 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  24383.                 $err = System::mkdir(array('-p', $tmpdir));
  24384.                 PEAR::staticPopErrorHandling();
  24385.                 if (PEAR::isError($err)) {
  24386.                     return $this->raiseError('channel-add: temp_dir does not exist: "' .
  24387.                         $tmpdir . 
  24388.                         '" - You can change this location with "pear config-set temp_dir"');
  24389.                 }
  24390.             }
  24391.             if (!is_writable($tmpdir)) {
  24392.                 return $this->raiseError('channel-add: temp_dir is not writable: "' .
  24393.                     $tmpdir . 
  24394.                     '" - You can change this location with "pear config-set temp_dir"');
  24395.             }
  24396.             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  24397.             $loc = $downloader->downloadHttp($params[0], $this->ui, $tmpdir, null, false);
  24398.             PEAR::staticPopErrorHandling();
  24399.             if (PEAR::isError($loc)) {
  24400.                 return $this->raiseError('channel-add: Cannot open "' . $params[0] .
  24401.                     '" (' . $loc->getMessage() . ')');
  24402.             } else {
  24403.                 list($loc, $lastmodified) = $loc;
  24404.                 $contents = implode('', file($loc));
  24405.             }
  24406.         } else {
  24407.             $lastmodified = $fp = false;
  24408.             if (file_exists($params[0])) {
  24409.                 $fp = fopen($params[0], 'r');
  24410.             }
  24411.             if (!$fp) {
  24412.                 return $this->raiseError('channel-add: cannot open "' . $params[0] . '"');
  24413.             }
  24414.             $contents = '';
  24415.             while (!feof($fp)) {
  24416.                 $contents .= fread($fp, 1024);
  24417.             }
  24418.             fclose($fp);
  24419.         }
  24420.         if (!class_exists('PEAR_ChannelFile')) {
  24421.             require_once 'PEAR/ChannelFile.php';
  24422.         }
  24423.         $channel = new PEAR_ChannelFile;
  24424.         PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  24425.         $result = $channel->fromXmlString($contents);
  24426.         PEAR::staticPopErrorHandling();
  24427.         if (!$result) {
  24428.             $exit = false;
  24429.             if (count($errors = $channel->getErrors(true))) {
  24430.                 foreach ($errors as $error) {
  24431.                     $this->ui->outputData(ucfirst($error['level'] . ': ' . $error['message']));
  24432.                     if (!$exit) {
  24433.                         $exit = $error['level'] == 'error' ? true : false;
  24434.                     }
  24435.                 }
  24436.                 if ($exit) {
  24437.                     return $this->raiseError('channel-add: invalid channel.xml file');
  24438.                 }
  24439.             }
  24440.         }
  24441.         $reg = &$this->config->getRegistry();
  24442.         if ($reg->channelExists($channel->getName())) {
  24443.             return $this->raiseError('channel-add: Channel "' . $channel->getName() .
  24444.                 '" exists, use channel-update to update entry');
  24445.         }
  24446.         $ret = $reg->addChannel($channel, $lastmodified);
  24447.         if (PEAR::isError($ret)) {
  24448.             return $ret;
  24449.         }
  24450.         if (!$ret) {
  24451.             return $this->raiseError('channel-add: adding Channel "' . $channel->getName() .
  24452.                 '" to registry failed');
  24453.         }
  24454.         $this->config->setChannels($reg->listChannels());
  24455.         $this->config->writeConfigFile();
  24456.         $this->ui->outputData('Adding Channel "' . $channel->getName() . '" succeeded', $command);
  24457.     }
  24458.  
  24459.     function doUpdate($command, $options, $params)
  24460.     {
  24461.         $tmpdir = $this->config->get('temp_dir');
  24462.         if (!file_exists($tmpdir)) {
  24463.             require_once 'System.php';
  24464.             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  24465.             $err = System::mkdir(array('-p', $tmpdir));
  24466.             PEAR::staticPopErrorHandling();
  24467.             if (PEAR::isError($err)) {
  24468.                 return $this->raiseError('channel-add: temp_dir does not exist: "' .
  24469.                     $tmpdir . 
  24470.                     '" - You can change this location with "pear config-set temp_dir"');
  24471.             }
  24472.         }
  24473.         if (!is_writable($tmpdir)) {
  24474.             return $this->raiseError('channel-add: temp_dir is not writable: "' .
  24475.                 $tmpdir . 
  24476.                 '" - You can change this location with "pear config-set temp_dir"');
  24477.         }
  24478.         $reg = &$this->config->getRegistry();
  24479.         if (sizeof($params) != 1) {
  24480.             return $this->raiseError("No channel file specified");
  24481.         }
  24482.         $lastmodified = false;
  24483.         if ((!file_exists($params[0]) || is_dir($params[0]))
  24484.               && $reg->channelExists(strtolower($params[0]))) {
  24485.             $c = $reg->getChannel(strtolower($params[0]));
  24486.             if (PEAR::isError($c)) {
  24487.                 return $this->raiseError($c);
  24488.             }
  24489.             $this->ui->outputData("Updating channel \"$params[0]\"", $command);
  24490.             $dl = &$this->getDownloader(array());
  24491.             // if force is specified, use a timestamp of "1" to force retrieval
  24492.             $lastmodified = isset($options['force']) ? false : $c->lastModified();
  24493.             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  24494.             $contents = $dl->downloadHttp('http://' . $c->getName() . '/channel.xml',
  24495.                 $this->ui, $tmpdir, null, $lastmodified);
  24496.             PEAR::staticPopErrorHandling();
  24497.             if (PEAR::isError($contents)) {
  24498.                 return $this->raiseError('Cannot retrieve channel.xml for channel "' .
  24499.                     $c->getName() . '" (' . $contents->getMessage() . ')');
  24500.             }
  24501.             list($contents, $lastmodified) = $contents;
  24502.             if (!$contents) {
  24503.                 $this->ui->outputData("Channel \"$params[0]\" is up to date");
  24504.                 return;
  24505.             }
  24506.             $contents = implode('', file($contents));
  24507.             if (!class_exists('PEAR_ChannelFile')) {
  24508.                 require_once 'PEAR/ChannelFile.php';
  24509.             }
  24510.             $channel = new PEAR_ChannelFile;
  24511.             $channel->fromXmlString($contents);
  24512.             if (!$channel->getErrors()) {
  24513.                 // security check: is the downloaded file for the channel we got it from?
  24514.                 if (strtolower($channel->getName()) != strtolower($c->getName())) {
  24515.                     if (isset($options['force'])) {
  24516.                         $this->ui->log(0, 'WARNING: downloaded channel definition file' .
  24517.                             ' for channel "' . $channel->getName() . '" from channel "' .
  24518.                             strtolower($c->getName()) . '"');
  24519.                     } else {
  24520.                         return $this->raiseError('ERROR: downloaded channel definition file' .
  24521.                             ' for channel "' . $channel->getName() . '" from channel "' .
  24522.                             strtolower($c->getName()) . '"');
  24523.                     }
  24524.                 }
  24525.             }
  24526.         } else {
  24527.             if (strpos($params[0], '://')) {
  24528.                 $dl = &$this->getDownloader();
  24529.                 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  24530.                 $loc = $dl->downloadHttp($params[0],
  24531.                     $this->ui, $tmpdir, null, $lastmodified);
  24532.                 PEAR::staticPopErrorHandling();
  24533.                 if (PEAR::isError($loc)) {
  24534.                     return $this->raiseError("Cannot open " . $params[0] .
  24535.                          ' (' . $loc->getMessage() . ')');
  24536.                 } else {
  24537.                     list($loc, $lastmodified) = $loc;
  24538.                     $contents = implode('', file($loc));
  24539.                 }
  24540.             } else {
  24541.                 $fp = false;
  24542.                 if (file_exists($params[0])) {
  24543.                     $fp = fopen($params[0], 'r');
  24544.                 }
  24545.                 if (!$fp) {
  24546.                     return $this->raiseError("Cannot open " . $params[0]);
  24547.                 }
  24548.                 $contents = '';
  24549.                 while (!feof($fp)) {
  24550.                     $contents .= fread($fp, 1024);
  24551.                 }
  24552.                 fclose($fp);
  24553.             }
  24554.             if (!class_exists('PEAR_ChannelFile')) {
  24555.                 require_once 'PEAR/ChannelFile.php';
  24556.             }
  24557.             $channel = new PEAR_ChannelFile;
  24558.             $channel->fromXmlString($contents);
  24559.         }
  24560.         $exit = false;
  24561.         if (count($errors = $channel->getErrors(true))) {
  24562.             foreach ($errors as $error) {
  24563.                 $this->ui->outputData(ucfirst($error['level'] . ': ' . $error['message']));
  24564.                 if (!$exit) {
  24565.                     $exit = $error['level'] == 'error' ? true : false;
  24566.                 }
  24567.             }
  24568.             if ($exit) {
  24569.                 return $this->raiseError('Invalid channel.xml file');
  24570.             }
  24571.         }
  24572.         if (!$reg->channelExists($channel->getName())) {
  24573.             return $this->raiseError('Error: Channel "' . $channel->getName() .
  24574.                 '" does not exist, use channel-add to add an entry');
  24575.         }
  24576.         $ret = $reg->updateChannel($channel, $lastmodified);
  24577.         if (PEAR::isError($ret)) {
  24578.             return $ret;
  24579.         }
  24580.         if (!$ret) {
  24581.             return $this->raiseError('Updating Channel "' . $channel->getName() .
  24582.                 '" in registry failed');
  24583.         }
  24584.         $this->config->setChannels($reg->listChannels());
  24585.         $this->config->writeConfigFile();
  24586.         $this->ui->outputData('Update of Channel "' . $channel->getName() . '" succeeded');
  24587.     }
  24588.  
  24589.     function &getDownloader()
  24590.     {
  24591.         if (!class_exists('PEAR_Downloader')) {
  24592.             require_once 'PEAR/Downloader.php';
  24593.         }
  24594.         $a = new PEAR_Downloader($this->ui, array(), $this->config);
  24595.         return $a;
  24596.     }
  24597.  
  24598.     function doAlias($command, $options, $params)
  24599.     {
  24600.         $reg = &$this->config->getRegistry();
  24601.         if (sizeof($params) == 1) {
  24602.             return $this->raiseError('No channel alias specified');
  24603.         }
  24604.         if (sizeof($params) != 2) {
  24605.             return $this->raiseError(
  24606.                 'Invalid format, correct is: channel-alias channel alias');
  24607.         }
  24608.         if (!$reg->channelExists($params[0], true)) {
  24609.             if ($reg->isAlias($params[0])) {
  24610.                 $extra = ' (use "channel-alias ' . $reg->channelName($params[0]) . ' ' .
  24611.                     strtolower($params[1]) . '")';
  24612.             } else {
  24613.                 $extra = '';
  24614.             }
  24615.             return $this->raiseError('"' . $params[0] . '" is not a valid channel' . $extra);
  24616.         }
  24617.         if ($reg->isAlias($params[1])) {
  24618.             return $this->raiseError('Channel "' . $reg->channelName($params[1]) . '" is ' .
  24619.                 'already aliased to "' . strtolower($params[1]) . '", cannot re-alias');
  24620.         }
  24621.         $chan = &$reg->getChannel($params[0]);
  24622.         if (PEAR::isError($chan)) {
  24623.             return $this->raiseError('Corrupt registry?  Error retrieving channel "' . $params[0] .
  24624.                 '" information (' . $chan->getMessage() . ')');
  24625.         }
  24626.         // make it a local alias
  24627.         if (!$chan->setAlias(strtolower($params[1]), true)) {
  24628.             return $this->raiseError('Alias "' . strtolower($params[1]) .
  24629.                 '" is not a valid channel alias');
  24630.         }
  24631.         $reg->updateChannel($chan);
  24632.         $this->ui->outputData('Channel "' . $chan->getName() . '" aliased successfully to "' .
  24633.             strtolower($params[1]) . '"');
  24634.     }
  24635.  
  24636.     /**
  24637.      * The channel-discover command
  24638.      *
  24639.      * @param string $command command name
  24640.      * @param array  $options option_name => value
  24641.      * @param array  $params  list of additional parameters.
  24642.      *               $params[0] should contain a string with either:
  24643.      *               - <channel name> or
  24644.      *               - <username>:<password>@<channel name>
  24645.      * @return null|PEAR_Error
  24646.      */
  24647.     function doDiscover($command, $options, $params)
  24648.     {
  24649.         $reg = &$this->config->getRegistry();
  24650.         if (sizeof($params) != 1) {
  24651.             return $this->raiseError("No channel server specified");
  24652.         }
  24653.         
  24654.         // Look for the possible input format "<username>:<password>@<channel>"
  24655.         if (preg_match('/^(.+):(.+)@(.+)\\z/', $params[0], $matches)) {
  24656.             $username = $matches[1];
  24657.             $password = $matches[2];
  24658.             $channel = $matches[3];
  24659.         } else {
  24660.             $channel = $params[0];
  24661.         }
  24662.         
  24663.         if ($reg->channelExists($channel)) {
  24664.             if ($reg->isAlias($channel)) {
  24665.                 return $this->raiseError("A channel alias named \"$channel\" " .
  24666.                     'already exists, aliasing channel "' . $reg->channelName($channel)
  24667.                     . '"');
  24668.             } else {
  24669.                 return $this->raiseError("Channel \"$channel\" is already initialized");
  24670.             }
  24671.         }
  24672.         $this->pushErrorHandling(PEAR_ERROR_RETURN);
  24673.         $err = $this->doAdd($command, $options, array('http://' . $channel . '/channel.xml'));
  24674.         $this->popErrorHandling();
  24675.         if (PEAR::isError($err)) {
  24676.             return $this->raiseError("Discovery of channel \"$channel\" failed (" .
  24677.                 $err->getMessage() . ')');
  24678.         }
  24679.         
  24680.         // Store username/password if they were given
  24681.         // Arguably we should do a logintest on the channel here, but since
  24682.         // that's awkward on a REST-based channel (even "pear login" doesn't
  24683.         // do it for those), and XML-RPC is deprecated, it's fairly pointless.
  24684.         if (isset($username)) {
  24685.             $this->config->set('username', $username, 'user', $channel);
  24686.             $this->config->set('password', $password, 'user', $channel);
  24687.             $this->config->store();
  24688.             $this->ui->outputData("Stored login for channel \"$channel\" using username \"$username\"", $command);
  24689.         }
  24690.         
  24691.         $this->ui->outputData("Discovery of channel \"$channel\" succeeded", $command);
  24692.     }
  24693. }
  24694. ?>
  24695. PEAR-1.7.1/PEAR/Command/Common.php100644   1750   1750       21300 10755221545  11561 <?php
  24696. /**
  24697.  * PEAR_Command_Common base class
  24698.  *
  24699.  * PHP versions 4 and 5
  24700.  *
  24701.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  24702.  * that is available through the world-wide-web at the following URI:
  24703.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  24704.  * the PHP License and are unable to obtain it through the web, please
  24705.  * send a note to license@php.net so we can mail you a copy immediately.
  24706.  *
  24707.  * @category   pear
  24708.  * @package    PEAR
  24709.  * @author     Stig Bakken <ssb@php.net>
  24710.  * @author     Greg Beaver <cellog@php.net>
  24711.  * @copyright  1997-2008 The PHP Group
  24712.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  24713.  * @version    CVS: $Id: Common.php,v 1.36 2008/01/03 20:26:36 cellog Exp $
  24714.  * @link       http://pear.php.net/package/PEAR
  24715.  * @since      File available since Release 0.1
  24716.  */
  24717.  
  24718. /**
  24719.  * base class
  24720.  */
  24721. require_once 'PEAR.php';
  24722.  
  24723. /**
  24724.  * PEAR commands base class
  24725.  *
  24726.  * @category   pear
  24727.  * @package    PEAR
  24728.  * @author     Stig Bakken <ssb@php.net>
  24729.  * @author     Greg Beaver <cellog@php.net>
  24730.  * @copyright  1997-2008 The PHP Group
  24731.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  24732.  * @version    Release: 1.7.1
  24733.  * @link       http://pear.php.net/package/PEAR
  24734.  * @since      Class available since Release 0.1
  24735.  */
  24736. class PEAR_Command_Common extends PEAR
  24737. {
  24738.     // {{{ properties
  24739.  
  24740.     /**
  24741.      * PEAR_Config object used to pass user system and configuration
  24742.      * on when executing commands
  24743.      *
  24744.      * @var PEAR_Config
  24745.      */
  24746.     var $config;
  24747.     /**
  24748.      * @var PEAR_Registry
  24749.      * @access protected
  24750.      */
  24751.     var $_registry;
  24752.  
  24753.     /**
  24754.      * User Interface object, for all interaction with the user.
  24755.      * @var object
  24756.      */
  24757.     var $ui;
  24758.  
  24759.     var $_deps_rel_trans = array(
  24760.                                  'lt' => '<',
  24761.                                  'le' => '<=',
  24762.                                  'eq' => '=',
  24763.                                  'ne' => '!=',
  24764.                                  'gt' => '>',
  24765.                                  'ge' => '>=',
  24766.                                  'has' => '=='
  24767.                                  );
  24768.  
  24769.     var $_deps_type_trans = array(
  24770.                                   'pkg' => 'package',
  24771.                                   'ext' => 'extension',
  24772.                                   'php' => 'PHP',
  24773.                                   'prog' => 'external program',
  24774.                                   'ldlib' => 'external library for linking',
  24775.                                   'rtlib' => 'external runtime library',
  24776.                                   'os' => 'operating system',
  24777.                                   'websrv' => 'web server',
  24778.                                   'sapi' => 'SAPI backend'
  24779.                                   );
  24780.  
  24781.     // }}}
  24782.     // {{{ constructor
  24783.  
  24784.     /**
  24785.      * PEAR_Command_Common constructor.
  24786.      *
  24787.      * @access public
  24788.      */
  24789.     function PEAR_Command_Common(&$ui, &$config)
  24790.     {
  24791.         parent::PEAR();
  24792.         $this->config = &$config;
  24793.         $this->ui = &$ui;
  24794.     }
  24795.  
  24796.     // }}}
  24797.  
  24798.     // {{{ getCommands()
  24799.  
  24800.     /**
  24801.      * Return a list of all the commands defined by this class.
  24802.      * @return array list of commands
  24803.      * @access public
  24804.      */
  24805.     function getCommands()
  24806.     {
  24807.         $ret = array();
  24808.         foreach (array_keys($this->commands) as $command) {
  24809.             $ret[$command] = $this->commands[$command]['summary'];
  24810.         }
  24811.         return $ret;
  24812.     }
  24813.  
  24814.     // }}}
  24815.     // {{{ getShortcuts()
  24816.  
  24817.     /**
  24818.      * Return a list of all the command shortcuts defined by this class.
  24819.      * @return array shortcut => command
  24820.      * @access public
  24821.      */
  24822.     function getShortcuts()
  24823.     {
  24824.         $ret = array();
  24825.         foreach (array_keys($this->commands) as $command) {
  24826.             if (isset($this->commands[$command]['shortcut'])) {
  24827.                 $ret[$this->commands[$command]['shortcut']] = $command;
  24828.             }
  24829.         }
  24830.         return $ret;
  24831.     }
  24832.  
  24833.     // }}}
  24834.     // {{{ getOptions()
  24835.  
  24836.     function getOptions($command)
  24837.     {
  24838.         $shortcuts = $this->getShortcuts();
  24839.         if (isset($shortcuts[$command])) {
  24840.             $command = $shortcuts[$command];
  24841.         }
  24842.         if (isset($this->commands[$command]) &&
  24843.               isset($this->commands[$command]['options'])) {
  24844.             return $this->commands[$command]['options'];
  24845.         } else {
  24846.             return null;
  24847.         }
  24848.     }
  24849.  
  24850.     // }}}
  24851.     // {{{ getGetoptArgs()
  24852.  
  24853.     function getGetoptArgs($command, &$short_args, &$long_args)
  24854.     {
  24855.         $short_args = "";
  24856.         $long_args = array();
  24857.         if (empty($this->commands[$command]) || empty($this->commands[$command]['options'])) {
  24858.             return;
  24859.         }
  24860.         reset($this->commands[$command]['options']);
  24861.         while (list($option, $info) = each($this->commands[$command]['options'])) {
  24862.             $larg = $sarg = '';
  24863.             if (isset($info['arg'])) {
  24864.                 if ($info['arg']{0} == '(') {
  24865.                     $larg = '==';
  24866.                     $sarg = '::';
  24867.                     $arg = substr($info['arg'], 1, -1);
  24868.                 } else {
  24869.                     $larg = '=';
  24870.                     $sarg = ':';
  24871.                     $arg = $info['arg'];
  24872.                 }
  24873.             }
  24874.             if (isset($info['shortopt'])) {
  24875.                 $short_args .= $info['shortopt'] . $sarg;
  24876.             }
  24877.             $long_args[] = $option . $larg;
  24878.         }
  24879.     }
  24880.  
  24881.     // }}}
  24882.     // {{{ getHelp()
  24883.     /**
  24884.     * Returns the help message for the given command
  24885.     *
  24886.     * @param string $command The command
  24887.     * @return mixed A fail string if the command does not have help or
  24888.     *               a two elements array containing [0]=>help string,
  24889.     *               [1]=> help string for the accepted cmd args
  24890.     */
  24891.     function getHelp($command)
  24892.     {
  24893.         $config = &PEAR_Config::singleton();
  24894.         if (!isset($this->commands[$command])) {
  24895.             return "No such command \"$command\"";
  24896.         }
  24897.         $help = null;
  24898.         if (isset($this->commands[$command]['doc'])) {
  24899.             $help = $this->commands[$command]['doc'];
  24900.         }
  24901.         if (empty($help)) {
  24902.             // XXX (cox) Fallback to summary if there is no doc (show both?)
  24903.             if (!isset($this->commands[$command]['summary'])) {
  24904.                 return "No help for command \"$command\"";
  24905.             }
  24906.             $help = $this->commands[$command]['summary'];
  24907.         }
  24908.         if (preg_match_all('/{config\s+([^\}]+)}/e', $help, $matches)) {
  24909.             foreach($matches[0] as $k => $v) {
  24910.                 $help = preg_replace("/$v/", $config->get($matches[1][$k]), $help);
  24911.             }
  24912.         }
  24913.         return array($help, $this->getHelpArgs($command));
  24914.     }
  24915.  
  24916.     // }}}
  24917.     // {{{ getHelpArgs()
  24918.     /**
  24919.     * Returns the help for the accepted arguments of a command
  24920.     *
  24921.     * @param  string $command
  24922.     * @return string The help string
  24923.     */
  24924.     function getHelpArgs($command)
  24925.     {
  24926.         if (isset($this->commands[$command]['options']) &&
  24927.             count($this->commands[$command]['options']))
  24928.         {
  24929.             $help = "Options:\n";
  24930.             foreach ($this->commands[$command]['options'] as $k => $v) {
  24931.                 if (isset($v['arg'])) {
  24932.                     if ($v['arg'][0] == '(') {
  24933.                         $arg = substr($v['arg'], 1, -1);
  24934.                         $sapp = " [$arg]";
  24935.                         $lapp = "[=$arg]";
  24936.                     } else {
  24937.                         $sapp = " $v[arg]";
  24938.                         $lapp = "=$v[arg]";
  24939.                     }
  24940.                 } else {
  24941.                     $sapp = $lapp = "";
  24942.                 }
  24943.                 if (isset($v['shortopt'])) {
  24944.                     $s = $v['shortopt'];
  24945.                     $help .= "  -$s$sapp, --$k$lapp\n";
  24946.                 } else {
  24947.                     $help .= "  --$k$lapp\n";
  24948.                 }
  24949.                 $p = "        ";
  24950.                 $doc = rtrim(str_replace("\n", "\n$p", $v['doc']));
  24951.                 $help .= "        $doc\n";
  24952.             }
  24953.             return $help;
  24954.         }
  24955.         return null;
  24956.     }
  24957.  
  24958.     // }}}
  24959.     // {{{ run()
  24960.  
  24961.     function run($command, $options, $params)
  24962.     {
  24963.         if (empty($this->commands[$command]['function'])) {
  24964.             // look for shortcuts
  24965.             foreach (array_keys($this->commands) as $cmd) {
  24966.                 if (isset($this->commands[$cmd]['shortcut']) && $this->commands[$cmd]['shortcut'] == $command) {
  24967.                     if (empty($this->commands[$cmd]['function'])) {
  24968.                         return $this->raiseError("unknown command `$command'");
  24969.                     } else {
  24970.                         $func = $this->commands[$cmd]['function'];
  24971.                     }
  24972.                     $command = $cmd;
  24973.                     break;
  24974.                 }
  24975.             }
  24976.         } else {
  24977.             $func = $this->commands[$command]['function'];
  24978.         }
  24979.         return $this->$func($command, $options, $params);
  24980.     }
  24981.  
  24982.     // }}}
  24983. }
  24984.  
  24985. ?>
  24986. PEAR-1.7.1/PEAR/Command/Config.xml100644   1750   1750        6466 10755221545  11547 <commands version="1.0">
  24987.  <config-show>
  24988.   <summary>Show All Settings</summary>
  24989.   <function>doConfigShow</function>
  24990.   <shortcut>csh</shortcut>
  24991.   <options>
  24992.    <channel>
  24993.     <shortopt>c</shortopt>
  24994.     <doc>show configuration variables for another channel</doc>
  24995.     <arg>CHAN</arg>
  24996.    </channel>
  24997.   </options>
  24998.   <doc>[layer]
  24999. Displays all configuration values.  An optional argument
  25000. may be used to tell which configuration layer to display.  Valid
  25001. configuration layers are "user", "system" and "default". To display
  25002. configurations for different channels, set the default_channel
  25003. configuration variable and run config-show again.
  25004. </doc>
  25005.  </config-show>
  25006.  <config-get>
  25007.   <summary>Show One Setting</summary>
  25008.   <function>doConfigGet</function>
  25009.   <shortcut>cg</shortcut>
  25010.   <options>
  25011.    <channel>
  25012.     <shortopt>c</shortopt>
  25013.     <doc>show configuration variables for another channel</doc>
  25014.     <arg>CHAN</arg>
  25015.    </channel>
  25016.   </options>
  25017.   <doc><parameter> [layer]
  25018. Displays the value of one configuration parameter.  The
  25019. first argument is the name of the parameter, an optional second argument
  25020. may be used to tell which configuration layer to look in.  Valid configuration
  25021. layers are "user", "system" and "default".  If no layer is specified, a value
  25022. will be picked from the first layer that defines the parameter, in the order
  25023. just specified.  The configuration value will be retrieved for the channel
  25024. specified by the default_channel configuration variable.
  25025. </doc>
  25026.  </config-get>
  25027.  <config-set>
  25028.   <summary>Change Setting</summary>
  25029.   <function>doConfigSet</function>
  25030.   <shortcut>cs</shortcut>
  25031.   <options>
  25032.    <channel>
  25033.     <shortopt>c</shortopt>
  25034.     <doc>show configuration variables for another channel</doc>
  25035.     <arg>CHAN</arg>
  25036.    </channel>
  25037.   </options>
  25038.   <doc><parameter> <value> [layer]
  25039. Sets the value of one configuration parameter.  The first argument is
  25040. the name of the parameter, the second argument is the new value.  Some
  25041. parameters are subject to validation, and the command will fail with
  25042. an error message if the new value does not make sense.  An optional
  25043. third argument may be used to specify in which layer to set the
  25044. configuration parameter.  The default layer is "user".  The
  25045. configuration value will be set for the current channel, which
  25046. is controlled by the default_channel configuration variable.
  25047. </doc>
  25048.  </config-set>
  25049.  <config-help>
  25050.   <summary>Show Information About Setting</summary>
  25051.   <function>doConfigHelp</function>
  25052.   <shortcut>ch</shortcut>
  25053.   <options />
  25054.   <doc>[parameter]
  25055. Displays help for a configuration parameter.  Without arguments it
  25056. displays help for all configuration parameters.
  25057. </doc>
  25058.  </config-help>
  25059.  <config-create>
  25060.   <summary>Create a Default configuration file</summary>
  25061.   <function>doConfigCreate</function>
  25062.   <shortcut>coc</shortcut>
  25063.   <options>
  25064.    <windows>
  25065.     <shortopt>w</shortopt>
  25066.     <doc>create a config file for a windows install</doc>
  25067.    </windows>
  25068.   </options>
  25069.   <doc><root path> <filename>
  25070. Create a default configuration file with all directory configuration
  25071. variables set to subdirectories of <root path>, and save it as <filename>.
  25072. This is useful especially for creating a configuration file for a remote
  25073. PEAR installation (using the --remoteconfig option of install, upgrade,
  25074. and uninstall).
  25075. </doc>
  25076.  </config-create>
  25077. </commands>PEAR-1.7.1/PEAR/Command/Config.php100644   1750   1750       36251 10755221545  11551 <?php
  25078. /**
  25079.  * PEAR_Command_Config (config-show, config-get, config-set, config-help, config-create commands)
  25080.  *
  25081.  * PHP versions 4 and 5
  25082.  *
  25083.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  25084.  * that is available through the world-wide-web at the following URI:
  25085.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  25086.  * the PHP License and are unable to obtain it through the web, please
  25087.  * send a note to license@php.net so we can mail you a copy immediately.
  25088.  *
  25089.  * @category   pear
  25090.  * @package    PEAR
  25091.  * @author     Stig Bakken <ssb@php.net>
  25092.  * @author     Greg Beaver <cellog@php.net>
  25093.  * @copyright  1997-2008 The PHP Group
  25094.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  25095.  * @version    CVS: $Id: Config.php,v 1.56 2008/01/03 20:26:36 cellog Exp $
  25096.  * @link       http://pear.php.net/package/PEAR
  25097.  * @since      File available since Release 0.1
  25098.  */
  25099.  
  25100. /**
  25101.  * base class
  25102.  */
  25103. require_once 'PEAR/Command/Common.php';
  25104.  
  25105. /**
  25106.  * PEAR commands for managing configuration data.
  25107.  *
  25108.  * @category   pear
  25109.  * @package    PEAR
  25110.  * @author     Stig Bakken <ssb@php.net>
  25111.  * @author     Greg Beaver <cellog@php.net>
  25112.  * @copyright  1997-2008 The PHP Group
  25113.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  25114.  * @version    Release: 1.7.1
  25115.  * @link       http://pear.php.net/package/PEAR
  25116.  * @since      Class available since Release 0.1
  25117.  */
  25118. class PEAR_Command_Config extends PEAR_Command_Common
  25119. {
  25120.     // {{{ properties
  25121.  
  25122.     var $commands = array(
  25123.         'config-show' => array(
  25124.             'summary' => 'Show All Settings',
  25125.             'function' => 'doConfigShow',
  25126.             'shortcut' => 'csh',
  25127.             'options' => array(
  25128.                 'channel' => array(
  25129.                     'shortopt' => 'c',
  25130.                     'doc' => 'show configuration variables for another channel',
  25131.                     'arg' => 'CHAN',
  25132.                     ),
  25133. ),
  25134.             'doc' => '[layer]
  25135. Displays all configuration values.  An optional argument
  25136. may be used to tell which configuration layer to display.  Valid
  25137. configuration layers are "user", "system" and "default". To display
  25138. configurations for different channels, set the default_channel
  25139. configuration variable and run config-show again.
  25140. ',
  25141.             ),
  25142.         'config-get' => array(
  25143.             'summary' => 'Show One Setting',
  25144.             'function' => 'doConfigGet',
  25145.             'shortcut' => 'cg',
  25146.             'options' => array(
  25147.                 'channel' => array(
  25148.                     'shortopt' => 'c',
  25149.                     'doc' => 'show configuration variables for another channel',
  25150.                     'arg' => 'CHAN',
  25151.                     ),
  25152. ),
  25153.             'doc' => '<parameter> [layer]
  25154. Displays the value of one configuration parameter.  The
  25155. first argument is the name of the parameter, an optional second argument
  25156. may be used to tell which configuration layer to look in.  Valid configuration
  25157. layers are "user", "system" and "default".  If no layer is specified, a value
  25158. will be picked from the first layer that defines the parameter, in the order
  25159. just specified.  The configuration value will be retrieved for the channel
  25160. specified by the default_channel configuration variable.
  25161. ',
  25162.             ),
  25163.         'config-set' => array(
  25164.             'summary' => 'Change Setting',
  25165.             'function' => 'doConfigSet',
  25166.             'shortcut' => 'cs',
  25167.             'options' => array(
  25168.                 'channel' => array(
  25169.                     'shortopt' => 'c',
  25170.                     'doc' => 'show configuration variables for another channel',
  25171.                     'arg' => 'CHAN',
  25172.                     ),
  25173. ),
  25174.             'doc' => '<parameter> <value> [layer]
  25175. Sets the value of one configuration parameter.  The first argument is
  25176. the name of the parameter, the second argument is the new value.  Some
  25177. parameters are subject to validation, and the command will fail with
  25178. an error message if the new value does not make sense.  An optional
  25179. third argument may be used to specify in which layer to set the
  25180. configuration parameter.  The default layer is "user".  The
  25181. configuration value will be set for the current channel, which
  25182. is controlled by the default_channel configuration variable.
  25183. ',
  25184.             ),
  25185.         'config-help' => array(
  25186.             'summary' => 'Show Information About Setting',
  25187.             'function' => 'doConfigHelp',
  25188.             'shortcut' => 'ch',
  25189.             'options' => array(),
  25190.             'doc' => '[parameter]
  25191. Displays help for a configuration parameter.  Without arguments it
  25192. displays help for all configuration parameters.
  25193. ',
  25194.            ),
  25195.         'config-create' => array(
  25196.             'summary' => 'Create a Default configuration file',
  25197.             'function' => 'doConfigCreate',
  25198.             'shortcut' => 'coc',
  25199.             'options' => array(
  25200.                 'windows' => array(
  25201.                     'shortopt' => 'w',
  25202.                     'doc' => 'create a config file for a windows install',
  25203.                     ),
  25204.             ),
  25205.             'doc' => '<root path> <filename>
  25206. Create a default configuration file with all directory configuration
  25207. variables set to subdirectories of <root path>, and save it as <filename>.
  25208. This is useful especially for creating a configuration file for a remote
  25209. PEAR installation (using the --remoteconfig option of install, upgrade,
  25210. and uninstall).
  25211. ',
  25212.             ),
  25213.         );
  25214.  
  25215.     // }}}
  25216.     // {{{ constructor
  25217.  
  25218.     /**
  25219.      * PEAR_Command_Config constructor.
  25220.      *
  25221.      * @access public
  25222.      */
  25223.     function PEAR_Command_Config(&$ui, &$config)
  25224.     {
  25225.         parent::PEAR_Command_Common($ui, $config);
  25226.     }
  25227.  
  25228.     // }}}
  25229.  
  25230.     // {{{ doConfigShow()
  25231.  
  25232.     function doConfigShow($command, $options, $params)
  25233.     {
  25234.         if (is_array($params)) {
  25235.             $layer = isset($params[0]) ? $params[0] : NULL;
  25236.         } else {
  25237.             $layer = NULL;
  25238.         }
  25239.  
  25240.         // $params[0] -> the layer
  25241.         if ($error = $this->_checkLayer($layer)) {
  25242.             return $this->raiseError("config-show:$error");
  25243.         }
  25244.         $keys = $this->config->getKeys();
  25245.         sort($keys);
  25246.         $channel = isset($options['channel']) ? $options['channel'] :
  25247.             $this->config->get('default_channel');
  25248.         $reg = &$this->config->getRegistry();
  25249.         if (!$reg->channelExists($channel)) {
  25250.             return $this->raiseError('Channel "' . $channel . '" does not exist');
  25251.         }
  25252.         $data = array('caption' => 'Configuration (channel ' . $channel . '):');
  25253.         foreach ($keys as $key) {
  25254.             $type = $this->config->getType($key);
  25255.             $value = $this->config->get($key, $layer, $channel);
  25256.             if ($type == 'password' && $value) {
  25257.                 $value = '********';
  25258.             }
  25259.             if ($value === false) {
  25260.                 $value = 'false';
  25261.             } elseif ($value === true) {
  25262.                 $value = 'true';
  25263.             }
  25264.             $data['data'][$this->config->getGroup($key)][] = array($this->config->getPrompt($key) , $key, $value);
  25265.         }
  25266.         foreach ($this->config->getLayers() as $layer) {
  25267.             $data['data']['Config Files'][] = array(ucfirst($layer) . ' Configuration File', 'Filename' , $this->config->getConfFile($layer));
  25268.         }
  25269.  
  25270.         $this->ui->outputData($data, $command);
  25271.         return true;
  25272.     }
  25273.  
  25274.     // }}}
  25275.     // {{{ doConfigGet()
  25276.  
  25277.     function doConfigGet($command, $options, $params)
  25278.     {
  25279.         if (!is_array($params)) {
  25280.             $args_cnt = 0;
  25281.         } else {
  25282.             $args_cnt  = count($params);
  25283.         }
  25284.  
  25285.         switch ($args_cnt) {
  25286.             case 1:
  25287.                 $config_key = $params[0];
  25288.                 $layer = NULL;
  25289.                 break;
  25290.             case 2:
  25291.                 $config_key = $params[0];
  25292.                 $layer = $params[1];
  25293.                 if ($error = $this->_checkLayer($layer)) {
  25294.                     return $this->raiseError("config-get:$error");
  25295.                 }
  25296.                 break;
  25297.             case 0:
  25298.             default:
  25299.                 return $this->raiseError("config-get expects 1 or 2 parameters");
  25300.         }
  25301.  
  25302.         $channel = isset($options['channel']) ? $options['channel'] : $this->config->get('default_channel');
  25303.         $reg = &$this->config->getRegistry();
  25304.  
  25305.         if (!$reg->channelExists($channel)) {
  25306.             return $this->raiseError('Channel "' . $channel . '" does not exist');
  25307.         }
  25308.  
  25309.         $this->ui->outputData($this->config->get($config_key, $layer, $channel), $command);
  25310.  
  25311.         return true;
  25312.     }
  25313.  
  25314.     // }}}
  25315.     // {{{ doConfigSet()
  25316.  
  25317.     function doConfigSet($command, $options, $params)
  25318.     {
  25319.         // $param[0] -> a parameter to set
  25320.         // $param[1] -> the value for the parameter
  25321.         // $param[2] -> the layer
  25322.         $failmsg = '';
  25323.         if (sizeof($params) < 2 || sizeof($params) > 3) {
  25324.             $failmsg .= "config-set expects 2 or 3 parameters";
  25325.             return PEAR::raiseError($failmsg);
  25326.         }
  25327.         if (isset($params[2]) && ($error = $this->_checkLayer($params[2]))) {
  25328.             $failmsg .= $error;
  25329.             return PEAR::raiseError("config-set:$failmsg");
  25330.         }
  25331.         $channel = isset($options['channel']) ? $options['channel'] :
  25332.             $this->config->get('default_channel');
  25333.         $reg = &$this->config->getRegistry();
  25334.         if (!$reg->channelExists($channel)) {
  25335.             return $this->raiseError('Channel "' . $channel . '" does not exist');
  25336.         }
  25337.         if ($params[0] == 'default_channel') {
  25338.             if (!$reg->channelExists($params[1])) {
  25339.                 return $this->raiseError('Channel "' . $params[1] . '" does not exist');
  25340.             }
  25341.         }
  25342.         if (count($params) == 2) {
  25343.             array_push($params, 'user');
  25344.             $layer = 'user';
  25345.         } else {
  25346.             $layer = $params[2];
  25347.         }
  25348.         array_push($params, $channel);
  25349.         if (!call_user_func_array(array(&$this->config, 'set'), $params))
  25350.         {
  25351.             array_pop($params);
  25352.             $failmsg = "config-set (" . implode(", ", $params) . ") failed, channel $channel";
  25353.         } else {
  25354.             $this->config->store($layer);
  25355.         }
  25356.         if ($failmsg) {
  25357.             return $this->raiseError($failmsg);
  25358.         }
  25359.         $this->ui->outputData('config-set succeeded', $command);
  25360.         return true;
  25361.     }
  25362.  
  25363.     // }}}
  25364.     // {{{ doConfigHelp()
  25365.  
  25366.     function doConfigHelp($command, $options, $params)
  25367.     {
  25368.         if (empty($params)) {
  25369.             $params = $this->config->getKeys();
  25370.         }
  25371.         $data['caption']  = "Config help" . ((count($params) == 1) ? " for $params[0]" : '');
  25372.         $data['headline'] = array('Name', 'Type', 'Description');
  25373.         $data['border']   = true;
  25374.         foreach ($params as $name) {
  25375.             $type = $this->config->getType($name);
  25376.             $docs = $this->config->getDocs($name);
  25377.             if ($type == 'set') {
  25378.                 $docs = rtrim($docs) . "\nValid set: " .
  25379.                     implode(' ', $this->config->getSetValues($name));
  25380.             }
  25381.             $data['data'][] = array($name, $type, $docs);
  25382.         }
  25383.         $this->ui->outputData($data, $command);
  25384.     }
  25385.  
  25386.     // }}}
  25387.     // {{{ doConfigCreate()
  25388.  
  25389.     function doConfigCreate($command, $options, $params)
  25390.     {
  25391.         if (count($params) != 2) {
  25392.             return PEAR::raiseError('config-create: must have 2 parameters, root path and ' .
  25393.                 'filename to save as');
  25394.         }
  25395.         $root = $params[0];
  25396.         // Clean up the DIRECTORY_SEPARATOR mess
  25397.         $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR;
  25398.         $root = preg_replace(array('!\\\\+!', '!/+!', "!$ds2+!"),
  25399.                              array('/', '/', '/'),
  25400.                             $root);
  25401.         if ($root{0} != '/') {
  25402.             if (isset($options['windows'])) {
  25403.                 if (!preg_match('/^[A-Za-z]:/', $root)) {
  25404.                     return PEAR::raiseError('Root directory must be an absolute path beginning ' .
  25405.                         'with "\\" or "C:\\", was: "' . $root . '"');
  25406.                 }
  25407.             } else {
  25408.                 return PEAR::raiseError('Root directory must be an absolute path beginning ' .
  25409.                     'with "/", was: "' . $root . '"');
  25410.             }
  25411.         }
  25412.         $windows = isset($options['windows']);
  25413.         if ($windows) {
  25414.             $root = str_replace('/', '\\', $root);
  25415.         }
  25416.         if (!file_exists($params[1])) {
  25417.             if (!@touch($params[1])) {
  25418.                 return PEAR::raiseError('Could not create "' . $params[1] . '"');
  25419.             }
  25420.         }
  25421.         $params[1] = realpath($params[1]);
  25422.         $config = &new PEAR_Config($params[1], '#no#system#config#', false, false);
  25423.         if ($root{strlen($root) - 1} == '/') {
  25424.             $root = substr($root, 0, strlen($root) - 1);
  25425.         }
  25426.         $config->noRegistry();
  25427.         $config->set('php_dir', $windows ? "$root\\pear\\php" : "$root/pear/php", 'user');
  25428.         $config->set('data_dir', $windows ? "$root\\pear\\data" : "$root/pear/data");
  25429.         $config->set('www_dir', $windows ? "$root\\pear\\www" : "$root/pear/www");
  25430.         $config->set('cfg_dir', $windows ? "$root\\pear\\cfg" : "$root/pear/cfg");
  25431.         $config->set('ext_dir', $windows ? "$root\\pear\\ext" : "$root/pear/ext");
  25432.         $config->set('doc_dir', $windows ? "$root\\pear\\docs" : "$root/pear/docs");
  25433.         $config->set('test_dir', $windows ? "$root\\pear\\tests" : "$root/pear/tests");
  25434.         $config->set('cache_dir', $windows ? "$root\\pear\\cache" : "$root/pear/cache");
  25435.         $config->set('download_dir', $windows ? "$root\\pear\\download" : "$root/pear/download");
  25436.         $config->set('temp_dir', $windows ? "$root\\pear\\temp" : "$root/pear/temp");
  25437.         $config->set('bin_dir', $windows ? "$root\\pear" : "$root/pear");
  25438.         $config->writeConfigFile();
  25439.         $this->_showConfig($config);
  25440.         $this->ui->outputData('Successfully created default configuration file "' . $params[1] . '"',
  25441.             $command);
  25442.     }
  25443.  
  25444.     // }}}
  25445.  
  25446.     function _showConfig(&$config)
  25447.     {
  25448.         $params = array('user');
  25449.         $keys = $config->getKeys();
  25450.         sort($keys);
  25451.         $channel = 'pear.php.net';
  25452.         $data = array('caption' => 'Configuration (channel ' . $channel . '):');
  25453.         foreach ($keys as $key) {
  25454.             $type = $config->getType($key);
  25455.             $value = $config->get($key, 'user', $channel);
  25456.             if ($type == 'password' && $value) {
  25457.                 $value = '********';
  25458.             }
  25459.             if ($value === false) {
  25460.                 $value = 'false';
  25461.             } elseif ($value === true) {
  25462.                 $value = 'true';
  25463.             }
  25464.             $data['data'][$config->getGroup($key)][] =
  25465.                 array($config->getPrompt($key) , $key, $value);
  25466.         }
  25467.         foreach ($config->getLayers() as $layer) {
  25468.             $data['data']['Config Files'][] =
  25469.                 array(ucfirst($layer) . ' Configuration File', 'Filename' ,
  25470.                     $config->getConfFile($layer));
  25471.         }
  25472.  
  25473.         $this->ui->outputData($data, 'config-show');
  25474.         return true;
  25475.     }
  25476.     // {{{ _checkLayer()
  25477.  
  25478.     /**
  25479.      * Checks if a layer is defined or not
  25480.      *
  25481.      * @param string $layer The layer to search for
  25482.      * @return mixed False on no error or the error message
  25483.      */
  25484.     function _checkLayer($layer = null)
  25485.     {
  25486.         if (!empty($layer) && $layer != 'default') {
  25487.             $layers = $this->config->getLayers();
  25488.             if (!in_array($layer, $layers)) {
  25489.                 return " only the layers: \"" . implode('" or "', $layers) . "\" are supported";
  25490.             }
  25491.         }
  25492.         return false;
  25493.     }
  25494.  
  25495.     // }}}
  25496. }
  25497.  
  25498. ?>
  25499. PEAR-1.7.1/PEAR/Command/Install.xml100644   1750   1750       17503 10755221545  11762 <commands version="1.0">
  25500.  <install>
  25501.   <summary>Install Package</summary>
  25502.   <function>doInstall</function>
  25503.   <shortcut>i</shortcut>
  25504.   <options>
  25505.    <force>
  25506.     <shortopt>f</shortopt>
  25507.     <doc>will overwrite newer installed packages</doc>
  25508.    </force>
  25509.    <loose>
  25510.     <shortopt>l</shortopt>
  25511.     <doc>do not check for recommended dependency version</doc>
  25512.    </loose>
  25513.    <nodeps>
  25514.     <shortopt>n</shortopt>
  25515.     <doc>ignore dependencies, install anyway</doc>
  25516.    </nodeps>
  25517.    <register-only>
  25518.     <shortopt>r</shortopt>
  25519.     <doc>do not install files, only register the package as installed</doc>
  25520.    </register-only>
  25521.    <soft>
  25522.     <shortopt>s</shortopt>
  25523.     <doc>soft install, fail silently, or upgrade if already installed</doc>
  25524.    </soft>
  25525.    <nobuild>
  25526.     <shortopt>B</shortopt>
  25527.     <doc>don't build C extensions</doc>
  25528.    </nobuild>
  25529.    <nocompress>
  25530.     <shortopt>Z</shortopt>
  25531.     <doc>request uncompressed files when downloading</doc>
  25532.    </nocompress>
  25533.    <installroot>
  25534.     <shortopt>R</shortopt>
  25535.     <arg>DIR</arg>
  25536.     <doc>root directory used when installing files (ala PHP's INSTALL_ROOT), use packagingroot for RPM</doc>
  25537.    </installroot>
  25538.    <packagingroot>
  25539.     <shortopt>P</shortopt>
  25540.     <arg>DIR</arg>
  25541.     <doc>root directory used when packaging files, like RPM packaging</doc>
  25542.    </packagingroot>
  25543.    <ignore-errors>
  25544.     <doc>force install even if there were errors</doc>
  25545.    </ignore-errors>
  25546.    <alldeps>
  25547.     <shortopt>a</shortopt>
  25548.     <doc>install all required and optional dependencies</doc>
  25549.    </alldeps>
  25550.    <onlyreqdeps>
  25551.     <shortopt>o</shortopt>
  25552.     <doc>install all required dependencies</doc>
  25553.    </onlyreqdeps>
  25554.    <offline>
  25555.     <shortopt>O</shortopt>
  25556.     <doc>do not attempt to download any urls or contact channels</doc>
  25557.    </offline>
  25558.    <pretend>
  25559.     <shortopt>p</shortopt>
  25560.     <doc>Only list the packages that would be downloaded</doc>
  25561.    </pretend>
  25562.   </options>
  25563.   <doc>[channel/]<package> ...
  25564. Installs one or more PEAR packages.  You can specify a package to
  25565. install in four ways:
  25566.  
  25567. "Package-1.0.tgz" : installs from a local file
  25568.  
  25569. "http://example.com/Package-1.0.tgz" : installs from
  25570. anywhere on the net.
  25571.  
  25572. "package.xml" : installs the package described in
  25573. package.xml.  Useful for testing, or for wrapping a PEAR package in
  25574. another package manager such as RPM.
  25575.  
  25576. "Package[-version/state][.tar]" : queries your default channel's server
  25577. ({config master_server}) and downloads the newest package with
  25578. the preferred quality/state ({config preferred_state}).
  25579.  
  25580. To retrieve Package version 1.1, use "Package-1.1," to retrieve
  25581. Package state beta, use "Package-beta."  To retrieve an uncompressed
  25582. file, append .tar (make sure there is no file by the same name first)
  25583.  
  25584. To download a package from another channel, prefix with the channel name like
  25585. "channel/Package"
  25586.  
  25587. More than one package may be specified at once.  It is ok to mix these
  25588. four ways of specifying packages.
  25589. </doc>
  25590.  </install>
  25591.  <upgrade>
  25592.   <summary>Upgrade Package</summary>
  25593.   <function>doInstall</function>
  25594.   <shortcut>up</shortcut>
  25595.   <options>
  25596.    <force>
  25597.     <shortopt>f</shortopt>
  25598.     <doc>overwrite newer installed packages</doc>
  25599.    </force>
  25600.    <loose>
  25601.     <shortopt>l</shortopt>
  25602.     <doc>do not check for recommended dependency version</doc>
  25603.    </loose>
  25604.    <nodeps>
  25605.     <shortopt>n</shortopt>
  25606.     <doc>ignore dependencies, upgrade anyway</doc>
  25607.    </nodeps>
  25608.    <register-only>
  25609.     <shortopt>r</shortopt>
  25610.     <doc>do not install files, only register the package as upgraded</doc>
  25611.    </register-only>
  25612.    <nobuild>
  25613.     <shortopt>B</shortopt>
  25614.     <doc>don't build C extensions</doc>
  25615.    </nobuild>
  25616.    <nocompress>
  25617.     <shortopt>Z</shortopt>
  25618.     <doc>request uncompressed files when downloading</doc>
  25619.    </nocompress>
  25620.    <installroot>
  25621.     <shortopt>R</shortopt>
  25622.     <arg>DIR</arg>
  25623.     <doc>root directory used when installing files (ala PHP's INSTALL_ROOT)</doc>
  25624.    </installroot>
  25625.    <ignore-errors>
  25626.     <doc>force install even if there were errors</doc>
  25627.    </ignore-errors>
  25628.    <alldeps>
  25629.     <shortopt>a</shortopt>
  25630.     <doc>install all required and optional dependencies</doc>
  25631.    </alldeps>
  25632.    <onlyreqdeps>
  25633.     <shortopt>o</shortopt>
  25634.     <doc>install all required dependencies</doc>
  25635.    </onlyreqdeps>
  25636.    <offline>
  25637.     <shortopt>O</shortopt>
  25638.     <doc>do not attempt to download any urls or contact channels</doc>
  25639.    </offline>
  25640.    <pretend>
  25641.     <shortopt>p</shortopt>
  25642.     <doc>Only list the packages that would be downloaded</doc>
  25643.    </pretend>
  25644.   </options>
  25645.   <doc><package> ...
  25646. Upgrades one or more PEAR packages.  See documentation for the
  25647. "install" command for ways to specify a package.
  25648.  
  25649. When upgrading, your package will be updated if the provided new
  25650. package has a higher version number (use the -f option if you need to
  25651. upgrade anyway).
  25652.  
  25653. More than one package may be specified at once.
  25654. </doc>
  25655.  </upgrade>
  25656.  <upgrade-all>
  25657.   <summary>Upgrade All Packages</summary>
  25658.   <function>doInstall</function>
  25659.   <shortcut>ua</shortcut>
  25660.   <options>
  25661.    <nodeps>
  25662.     <shortopt>n</shortopt>
  25663.     <doc>ignore dependencies, upgrade anyway</doc>
  25664.    </nodeps>
  25665.    <register-only>
  25666.     <shortopt>r</shortopt>
  25667.     <doc>do not install files, only register the package as upgraded</doc>
  25668.    </register-only>
  25669.    <nobuild>
  25670.     <shortopt>B</shortopt>
  25671.     <doc>don't build C extensions</doc>
  25672.    </nobuild>
  25673.    <nocompress>
  25674.     <shortopt>Z</shortopt>
  25675.     <doc>request uncompressed files when downloading</doc>
  25676.    </nocompress>
  25677.    <installroot>
  25678.     <shortopt>R</shortopt>
  25679.     <arg>DIR</arg>
  25680.     <doc>root directory used when installing files (ala PHP's INSTALL_ROOT)</doc>
  25681.    </installroot>
  25682.    <ignore-errors>
  25683.     <doc>force install even if there were errors</doc>
  25684.    </ignore-errors>
  25685.    <loose>
  25686.     <doc>do not check for recommended dependency version</doc>
  25687.    </loose>
  25688.   </options>
  25689.   <doc>
  25690. Upgrades all packages that have a newer release available.  Upgrades are
  25691. done only if there is a release available of the state specified in
  25692. "preferred_state" (currently {config preferred_state}), or a state considered
  25693. more stable.
  25694. </doc>
  25695.  </upgrade-all>
  25696.  <uninstall>
  25697.   <summary>Un-install Package</summary>
  25698.   <function>doUninstall</function>
  25699.   <shortcut>un</shortcut>
  25700.   <options>
  25701.    <nodeps>
  25702.     <shortopt>n</shortopt>
  25703.     <doc>ignore dependencies, uninstall anyway</doc>
  25704.    </nodeps>
  25705.    <register-only>
  25706.     <shortopt>r</shortopt>
  25707.     <doc>do not remove files, only register the packages as not installed</doc>
  25708.    </register-only>
  25709.    <installroot>
  25710.     <shortopt>R</shortopt>
  25711.     <arg>DIR</arg>
  25712.     <doc>root directory used when installing files (ala PHP's INSTALL_ROOT)</doc>
  25713.    </installroot>
  25714.    <ignore-errors>
  25715.     <doc>force install even if there were errors</doc>
  25716.    </ignore-errors>
  25717.    <offline>
  25718.     <shortopt>O</shortopt>
  25719.     <doc>do not attempt to uninstall remotely</doc>
  25720.    </offline>
  25721.   </options>
  25722.   <doc>[channel/]<package> ...
  25723. Uninstalls one or more PEAR packages.  More than one package may be
  25724. specified at once.  Prefix with channel name to uninstall from a
  25725. channel not in your default channel ({config default_channel})
  25726. </doc>
  25727.  </uninstall>
  25728.  <bundle>
  25729.   <summary>Unpacks a Pecl Package</summary>
  25730.   <function>doBundle</function>
  25731.   <shortcut>bun</shortcut>
  25732.   <options>
  25733.    <destination>
  25734.     <shortopt>d</shortopt>
  25735.     <arg>DIR</arg>
  25736.     <doc>Optional destination directory for unpacking (defaults to current path or "ext" if exists)</doc>
  25737.    </destination>
  25738.    <force>
  25739.     <shortopt>f</shortopt>
  25740.     <doc>Force the unpacking even if there were errors in the package</doc>
  25741.    </force>
  25742.   </options>
  25743.   <doc><package>
  25744. Unpacks a Pecl Package into the selected location. It will download the
  25745. package if needed.
  25746. </doc>
  25747.  </bundle>
  25748.  <run-scripts>
  25749.   <summary>Run Post-Install Scripts bundled with a package</summary>
  25750.   <function>doRunScripts</function>
  25751.   <shortcut>rs</shortcut>
  25752.   <options />
  25753.   <doc><package>
  25754. Run post-installation scripts in package <package>, if any exist.
  25755. </doc>
  25756.  </run-scripts>
  25757. </commands>PEAR-1.7.1/PEAR/Command/Install.php100644   1750   1750      141703 10755221545  11771 <?php
  25758. /**
  25759.  * PEAR_Command_Install (install, upgrade, upgrade-all, uninstall, bundle, run-scripts commands)
  25760.  *
  25761.  * PHP versions 4 and 5
  25762.  *
  25763.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  25764.  * that is available through the world-wide-web at the following URI:
  25765.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  25766.  * the PHP License and are unable to obtain it through the web, please
  25767.  * send a note to license@php.net so we can mail you a copy immediately.
  25768.  *
  25769.  * @category   pear
  25770.  * @package    PEAR
  25771.  * @author     Stig Bakken <ssb@php.net>
  25772.  * @author     Greg Beaver <cellog@php.net>
  25773.  * @copyright  1997-2008 The PHP Group
  25774.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  25775.  * @version    CVS: $Id: Install.php,v 1.140 2008/01/29 03:21:01 cellog Exp $
  25776.  * @link       http://pear.php.net/package/PEAR
  25777.  * @since      File available since Release 0.1
  25778.  */
  25779.  
  25780. /**
  25781.  * base class
  25782.  */
  25783. require_once 'PEAR/Command/Common.php';
  25784.  
  25785. /**
  25786.  * PEAR commands for installation or deinstallation/upgrading of
  25787.  * packages.
  25788.  *
  25789.  * @category   pear
  25790.  * @package    PEAR
  25791.  * @author     Stig Bakken <ssb@php.net>
  25792.  * @author     Greg Beaver <cellog@php.net>
  25793.  * @copyright  1997-2008 The PHP Group
  25794.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  25795.  * @version    Release: 1.7.1
  25796.  * @link       http://pear.php.net/package/PEAR
  25797.  * @since      Class available since Release 0.1
  25798.  */
  25799. class PEAR_Command_Install extends PEAR_Command_Common
  25800. {
  25801.     // {{{ properties
  25802.  
  25803.     var $commands = array(
  25804.         'install' => array(
  25805.             'summary' => 'Install Package',
  25806.             'function' => 'doInstall',
  25807.             'shortcut' => 'i',
  25808.             'options' => array(
  25809.                 'force' => array(
  25810.                     'shortopt' => 'f',
  25811.                     'doc' => 'will overwrite newer installed packages',
  25812.                     ),
  25813.                 'loose' => array(
  25814.                     'shortopt' => 'l',
  25815.                     'doc' => 'do not check for recommended dependency version',
  25816.                     ),
  25817.                 'nodeps' => array(
  25818.                     'shortopt' => 'n',
  25819.                     'doc' => 'ignore dependencies, install anyway',
  25820.                     ),
  25821.                 'register-only' => array(
  25822.                     'shortopt' => 'r',
  25823.                     'doc' => 'do not install files, only register the package as installed',
  25824.                     ),
  25825.                 'soft' => array(
  25826.                     'shortopt' => 's',
  25827.                     'doc' => 'soft install, fail silently, or upgrade if already installed',
  25828.                     ),
  25829.                 'nobuild' => array(
  25830.                     'shortopt' => 'B',
  25831.                     'doc' => 'don\'t build C extensions',
  25832.                     ),
  25833.                 'nocompress' => array(
  25834.                     'shortopt' => 'Z',
  25835.                     'doc' => 'request uncompressed files when downloading',
  25836.                     ),
  25837.                 'installroot' => array(
  25838.                     'shortopt' => 'R',
  25839.                     'arg' => 'DIR',
  25840.                     'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM',
  25841.                     ),
  25842.                 'packagingroot' => array(
  25843.                     'shortopt' => 'P',
  25844.                     'arg' => 'DIR',
  25845.                     'doc' => 'root directory used when packaging files, like RPM packaging',
  25846.                     ),
  25847.                 'ignore-errors' => array(
  25848.                     'doc' => 'force install even if there were errors',
  25849.                     ),
  25850.                 'alldeps' => array(
  25851.                     'shortopt' => 'a',
  25852.                     'doc' => 'install all required and optional dependencies',
  25853.                     ),
  25854.                 'onlyreqdeps' => array(
  25855.                     'shortopt' => 'o',
  25856.                     'doc' => 'install all required dependencies',
  25857.                     ),
  25858.                 'offline' => array(
  25859.                     'shortopt' => 'O',
  25860.                     'doc' => 'do not attempt to download any urls or contact channels',
  25861.                     ),
  25862.                 'pretend' => array(
  25863.                     'shortopt' => 'p',
  25864.                     'doc' => 'Only list the packages that would be downloaded',
  25865.                     ),
  25866.                 ),
  25867.             'doc' => '[channel/]<package> ...
  25868. Installs one or more PEAR packages.  You can specify a package to
  25869. install in four ways:
  25870.  
  25871. "Package-1.0.tgz" : installs from a local file
  25872.  
  25873. "http://example.com/Package-1.0.tgz" : installs from
  25874. anywhere on the net.
  25875.  
  25876. "package.xml" : installs the package described in
  25877. package.xml.  Useful for testing, or for wrapping a PEAR package in
  25878. another package manager such as RPM.
  25879.  
  25880. "Package[-version/state][.tar]" : queries your default channel\'s server
  25881. ({config master_server}) and downloads the newest package with
  25882. the preferred quality/state ({config preferred_state}).
  25883.  
  25884. To retrieve Package version 1.1, use "Package-1.1," to retrieve
  25885. Package state beta, use "Package-beta."  To retrieve an uncompressed
  25886. file, append .tar (make sure there is no file by the same name first)
  25887.  
  25888. To download a package from another channel, prefix with the channel name like
  25889. "channel/Package"
  25890.  
  25891. More than one package may be specified at once.  It is ok to mix these
  25892. four ways of specifying packages.
  25893. '),
  25894.         'upgrade' => array(
  25895.             'summary' => 'Upgrade Package',
  25896.             'function' => 'doInstall',
  25897.             'shortcut' => 'up',
  25898.             'options' => array(
  25899.                 'force' => array(
  25900.                     'shortopt' => 'f',
  25901.                     'doc' => 'overwrite newer installed packages',
  25902.                     ),
  25903.                 'loose' => array(
  25904.                     'shortopt' => 'l',
  25905.                     'doc' => 'do not check for recommended dependency version',
  25906.                     ),
  25907.                 'nodeps' => array(
  25908.                     'shortopt' => 'n',
  25909.                     'doc' => 'ignore dependencies, upgrade anyway',
  25910.                     ),
  25911.                 'register-only' => array(
  25912.                     'shortopt' => 'r',
  25913.                     'doc' => 'do not install files, only register the package as upgraded',
  25914.                     ),
  25915.                 'nobuild' => array(
  25916.                     'shortopt' => 'B',
  25917.                     'doc' => 'don\'t build C extensions',
  25918.                     ),
  25919.                 'nocompress' => array(
  25920.                     'shortopt' => 'Z',
  25921.                     'doc' => 'request uncompressed files when downloading',
  25922.                     ),
  25923.                 'installroot' => array(
  25924.                     'shortopt' => 'R',
  25925.                     'arg' => 'DIR',
  25926.                     'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)',
  25927.                     ),
  25928.                 'ignore-errors' => array(
  25929.                     'doc' => 'force install even if there were errors',
  25930.                     ),
  25931.                 'alldeps' => array(
  25932.                     'shortopt' => 'a',
  25933.                     'doc' => 'install all required and optional dependencies',
  25934.                     ),
  25935.                 'onlyreqdeps' => array(
  25936.                     'shortopt' => 'o',
  25937.                     'doc' => 'install all required dependencies',
  25938.                     ),
  25939.                 'offline' => array(
  25940.                     'shortopt' => 'O',
  25941.                     'doc' => 'do not attempt to download any urls or contact channels',
  25942.                     ),
  25943.                 'pretend' => array(
  25944.                     'shortopt' => 'p',
  25945.                     'doc' => 'Only list the packages that would be downloaded',
  25946.                     ),
  25947.                 ),
  25948.             'doc' => '<package> ...
  25949. Upgrades one or more PEAR packages.  See documentation for the
  25950. "install" command for ways to specify a package.
  25951.  
  25952. When upgrading, your package will be updated if the provided new
  25953. package has a higher version number (use the -f option if you need to
  25954. upgrade anyway).
  25955.  
  25956. More than one package may be specified at once.
  25957. '),
  25958.         'upgrade-all' => array(
  25959.             'summary' => 'Upgrade All Packages',
  25960.             'function' => 'doUpgradeAll',
  25961.             'shortcut' => 'ua',
  25962.             'options' => array(
  25963.                 'nodeps' => array(
  25964.                     'shortopt' => 'n',
  25965.                     'doc' => 'ignore dependencies, upgrade anyway',
  25966.                     ),
  25967.                 'register-only' => array(
  25968.                     'shortopt' => 'r',
  25969.                     'doc' => 'do not install files, only register the package as upgraded',
  25970.                     ),
  25971.                 'nobuild' => array(
  25972.                     'shortopt' => 'B',
  25973.                     'doc' => 'don\'t build C extensions',
  25974.                     ),
  25975.                 'nocompress' => array(
  25976.                     'shortopt' => 'Z',
  25977.                     'doc' => 'request uncompressed files when downloading',
  25978.                     ),
  25979.                 'installroot' => array(
  25980.                     'shortopt' => 'R',
  25981.                     'arg' => 'DIR',
  25982.                     'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM',
  25983.                     ),
  25984.                 'ignore-errors' => array(
  25985.                     'doc' => 'force install even if there were errors',
  25986.                     ),
  25987.                 'loose' => array(
  25988.                     'doc' => 'do not check for recommended dependency version',
  25989.                     ),
  25990.                 ),
  25991.             'doc' => '
  25992. Upgrades all packages that have a newer release available.  Upgrades are
  25993. done only if there is a release available of the state specified in
  25994. "preferred_state" (currently {config preferred_state}), or a state considered
  25995. more stable.
  25996. '),
  25997.         'uninstall' => array(
  25998.             'summary' => 'Un-install Package',
  25999.             'function' => 'doUninstall',
  26000.             'shortcut' => 'un',
  26001.             'options' => array(
  26002.                 'nodeps' => array(
  26003.                     'shortopt' => 'n',
  26004.                     'doc' => 'ignore dependencies, uninstall anyway',
  26005.                     ),
  26006.                 'register-only' => array(
  26007.                     'shortopt' => 'r',
  26008.                     'doc' => 'do not remove files, only register the packages as not installed',
  26009.                     ),
  26010.                 'installroot' => array(
  26011.                     'shortopt' => 'R',
  26012.                     'arg' => 'DIR',
  26013.                     'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)',
  26014.                     ),
  26015.                 'ignore-errors' => array(
  26016.                     'doc' => 'force install even if there were errors',
  26017.                     ),
  26018.                 'offline' => array(
  26019.                     'shortopt' => 'O',
  26020.                     'doc' => 'do not attempt to uninstall remotely',
  26021.                     ),
  26022.                 ),
  26023.             'doc' => '[channel/]<package> ...
  26024. Uninstalls one or more PEAR packages.  More than one package may be
  26025. specified at once.  Prefix with channel name to uninstall from a
  26026. channel not in your default channel ({config default_channel})
  26027. '),
  26028.         'bundle' => array(
  26029.             'summary' => 'Unpacks a Pecl Package',
  26030.             'function' => 'doBundle',
  26031.             'shortcut' => 'bun',
  26032.             'options' => array(
  26033.                 'destination' => array(
  26034.                    'shortopt' => 'd',
  26035.                     'arg' => 'DIR',
  26036.                     'doc' => 'Optional destination directory for unpacking (defaults to current path or "ext" if exists)',
  26037.                     ),
  26038.                 'force' => array(
  26039.                     'shortopt' => 'f',
  26040.                     'doc' => 'Force the unpacking even if there were errors in the package',
  26041.                 ),
  26042.             ),
  26043.             'doc' => '<package>
  26044. Unpacks a Pecl Package into the selected location. It will download the
  26045. package if needed.
  26046. '),
  26047.         'run-scripts' => array(
  26048.             'summary' => 'Run Post-Install Scripts bundled with a package',
  26049.             'function' => 'doRunScripts',
  26050.             'shortcut' => 'rs',
  26051.             'options' => array(
  26052.             ),
  26053.             'doc' => '<package>
  26054. Run post-installation scripts in package <package>, if any exist.
  26055. '),
  26056.     );
  26057.  
  26058.     // }}}
  26059.     // {{{ constructor
  26060.  
  26061.     /**
  26062.      * PEAR_Command_Install constructor.
  26063.      *
  26064.      * @access public
  26065.      */
  26066.     function PEAR_Command_Install(&$ui, &$config)
  26067.     {
  26068.         parent::PEAR_Command_Common($ui, $config);
  26069.     }
  26070.  
  26071.     // }}}
  26072.  
  26073.     /**
  26074.      * For unit testing purposes
  26075.      */
  26076.     function &getDownloader(&$ui, $options, &$config)
  26077.     {
  26078.         if (!class_exists('PEAR_Downloader')) {
  26079.             require_once 'PEAR/Downloader.php';
  26080.         }
  26081.         $a = &new PEAR_Downloader($ui, $options, $config);
  26082.         return $a;
  26083.     }
  26084.  
  26085.     /**
  26086.      * For unit testing purposes
  26087.      */
  26088.     function &getInstaller(&$ui)
  26089.     {
  26090.         if (!class_exists('PEAR_Installer')) {
  26091.             require_once 'PEAR/Installer.php';
  26092.         }
  26093.         $a = &new PEAR_Installer($ui);
  26094.         return $a;
  26095.     }
  26096.  
  26097.     function enableExtension($binaries, $type)
  26098.     {
  26099.         if (!($phpini = $this->config->get('php_ini', null, 'pear.php.net'))) {
  26100.             return PEAR::raiseError('configuration option "php_ini" is not set to php.ini location');
  26101.         }
  26102.         $ini = $this->_parseIni($phpini);
  26103.         if (PEAR::isError($ini)) {
  26104.             return $ini;
  26105.         }
  26106.         $line = 0;
  26107.         if ($type == 'extsrc' || $type == 'extbin') {
  26108.             $search = 'extensions';
  26109.             $enable = 'extension';
  26110.         } else {
  26111.             $search = 'zend_extensions';
  26112.             ob_start();
  26113.             phpinfo(INFO_GENERAL);
  26114.             $info = ob_get_contents();
  26115.             ob_end_clean();
  26116.             $debug = function_exists('leak') ? '_debug' : '';
  26117.             $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : '';
  26118.             $enable = 'zend_extension' . $debug . $ts;
  26119.         }
  26120.         foreach ($ini[$search] as $line => $extension) {
  26121.             if (in_array($extension, $binaries, true) || in_array(
  26122.                   $ini['extension_dir'] . DIRECTORY_SEPARATOR . $extension, $binaries, true)) {
  26123.                 // already enabled - assume if one is, all are
  26124.                 return true;
  26125.             }
  26126.         }
  26127.         if ($line) {
  26128.             $newini = array_slice($ini['all'], 0, $line);
  26129.         } else {
  26130.             $newini = array();
  26131.         }
  26132.         foreach ($binaries as $binary) {
  26133.             if ($ini['extension_dir']) {
  26134.                 $binary = basename($binary);
  26135.             }
  26136.             $newini[] = $enable . '="' . $binary . '"' . (OS_UNIX ? "\n" : "\r\n");
  26137.         }
  26138.         $newini = array_merge($newini, array_slice($ini['all'], $line));
  26139.         $fp = @fopen($phpini, 'wb');
  26140.         if (!$fp) {
  26141.             return PEAR::raiseError('cannot open php.ini "' . $phpini . '" for writing');
  26142.         }
  26143.         foreach ($newini as $line) {
  26144.             fwrite($fp, $line);
  26145.         }
  26146.         fclose($fp);
  26147.         return true;
  26148.     }
  26149.  
  26150.     function disableExtension($binaries, $type)
  26151.     {
  26152.         if (!($phpini = $this->config->get('php_ini', null, 'pear.php.net'))) {
  26153.             return PEAR::raiseError('configuration option "php_ini" is not set to php.ini location');
  26154.         }
  26155.         $ini = $this->_parseIni($phpini);
  26156.         if (PEAR::isError($ini)) {
  26157.             return $ini;
  26158.         }
  26159.         $line = 0;
  26160.         if ($type == 'extsrc' || $type == 'extbin') {
  26161.             $search = 'extensions';
  26162.             $enable = 'extension';
  26163.         } else {
  26164.             $search = 'zend_extensions';
  26165.             ob_start();
  26166.             phpinfo(INFO_GENERAL);
  26167.             $info = ob_get_contents();
  26168.             ob_end_clean();
  26169.             $debug = function_exists('leak') ? '_debug' : '';
  26170.             $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : '';
  26171.             $enable = 'zend_extension' . $debug . $ts;
  26172.         }
  26173.         $found = false;
  26174.         foreach ($ini[$search] as $line => $extension) {
  26175.             if (in_array($extension, $binaries, true) || in_array(
  26176.                   $ini['extension_dir'] . DIRECTORY_SEPARATOR . $extension, $binaries, true)) {
  26177.                 $found = true;
  26178.                 break;
  26179.             }
  26180.         }
  26181.         if (!$found) {
  26182.             // not enabled
  26183.             return true;
  26184.         }
  26185.         $fp = @fopen($phpini, 'wb');
  26186.         if (!$fp) {
  26187.             return PEAR::raiseError('cannot open php.ini "' . $phpini . '" for writing');
  26188.         }
  26189.         if ($line) {
  26190.             $newini = array_slice($ini['all'], 0, $line);
  26191.             // delete the enable line
  26192.             $newini = array_merge($newini, array_slice($ini['all'], $line + 1));
  26193.         } else {
  26194.             $newini = array_slice($ini['all'], 1);
  26195.         }
  26196.         foreach ($newini as $line) {
  26197.             fwrite($fp, $line);
  26198.         }
  26199.         fclose($fp);
  26200.         return true;
  26201.     }
  26202.  
  26203.     function _parseIni($filename)
  26204.     {
  26205.         if (file_exists($filename)) {
  26206.             if (filesize($filename) > 300000) {
  26207.                 return PEAR::raiseError('php.ini "' . $filename . '" is too large, aborting');
  26208.             }
  26209.             ob_start();
  26210.             phpinfo(INFO_GENERAL);
  26211.             $info = ob_get_contents();
  26212.             ob_end_clean();
  26213.             $debug = function_exists('leak') ? '_debug' : '';
  26214.             $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : '';
  26215.             $zend_extension_line = 'zend_extension' . $debug . $ts;
  26216.             $all = @file($filename);
  26217.             if (!$all) {
  26218.                 return PEAR::raiseError('php.ini "' . $filename .'" could not be read');
  26219.             }
  26220.             $zend_extensions = $extensions = array();
  26221.             // assume this is right, but pull from the php.ini if it is found
  26222.             $extension_dir = ini_get('extension_dir');
  26223.             foreach ($all as $linenum => $line) {
  26224.                 $line = trim($line);
  26225.                 if (!$line) {
  26226.                     continue;
  26227.                 }
  26228.                 if ($line[0] == ';') {
  26229.                     continue;
  26230.                 }
  26231.                 if (strtolower(substr($line, 0, 13)) == 'extension_dir') {
  26232.                     $line = trim(substr($line, 13));
  26233.                     if ($line[0] == '=') {
  26234.                         $x = trim(substr($line, 1));
  26235.                         $x = explode(';', $x);
  26236.                         $extension_dir = str_replace('"', '', array_shift($x));
  26237.                         continue;
  26238.                     }
  26239.                 }
  26240.                 if (strtolower(substr($line, 0, 9)) == 'extension') {
  26241.                     $line = trim(substr($line, 9));
  26242.                     if ($line[0] == '=') {
  26243.                         $x = trim(substr($line, 1));
  26244.                         $x = explode(';', $x);
  26245.                         $extensions[$linenum] = str_replace('"', '', array_shift($x));
  26246.                         continue;
  26247.                     }
  26248.                 }
  26249.                 if (strtolower(substr($line, 0, strlen($zend_extension_line))) ==
  26250.                       $zend_extension_line) {
  26251.                     $line = trim(substr($line, strlen($zend_extension_line)));
  26252.                     if ($line[0] == '=') {
  26253.                         $x = trim(substr($line, 1));
  26254.                         $x = explode(';', $x);
  26255.                         $zend_extensions[$linenum] = str_replace('"', '', array_shift($x));
  26256.                         continue;
  26257.                     }
  26258.                 }
  26259.             }
  26260.             return array(
  26261.                 'extensions' => $extensions,
  26262.                 'zend_extensions' => $zend_extensions,
  26263.                 'extension_dir' => $extension_dir,
  26264.                 'all' => $all,
  26265.             );
  26266.         } else {
  26267.             return PEAR::raiseError('php.ini "' . $filename . '" does not exist');
  26268.         }
  26269.     }
  26270.  
  26271.     // {{{ doInstall()
  26272.  
  26273.     function doInstall($command, $options, $params)
  26274.     {
  26275.         if (!class_exists('PEAR_PackageFile')) {
  26276.             require_once 'PEAR/PackageFile.php';
  26277.         }
  26278.         if (empty($this->installer)) {
  26279.             $this->installer = &$this->getInstaller($this->ui);
  26280.         }
  26281.         if ($command == 'upgrade' || $command == 'upgrade-all') {
  26282.             $options['upgrade'] = true;
  26283.         } else {
  26284.             $packages = $params;
  26285.         }
  26286.         if (isset($options['installroot']) && isset($options['packagingroot'])) {
  26287.             return $this->raiseError('ERROR: cannot use both --installroot and --packagingroot');
  26288.         }
  26289.         $reg = &$this->config->getRegistry();
  26290.         $instreg = &$reg; // instreg used to check if package is installed
  26291.         if (isset($options['packagingroot']) && !isset($options['upgrade'])) {
  26292.             $packrootphp_dir = $this->installer->_prependPath(
  26293.                 $this->config->get('php_dir', null, 'pear.php.net'),
  26294.                 $options['packagingroot']);
  26295.             $instreg = new PEAR_Registry($packrootphp_dir); // other instreg!
  26296.  
  26297.             if ($this->config->get('verbose') > 2) {
  26298.                 $this->ui->outputData('using package root: ' . $options['packagingroot']);
  26299.             }
  26300.         }
  26301.         $abstractpackages = array();
  26302.         $otherpackages = array();
  26303.         // parse params
  26304.         PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  26305.         foreach($params as $param) {
  26306.             if (strpos($param, 'http://') === 0) {
  26307.                 $otherpackages[] = $param;
  26308.                 continue;
  26309.             }
  26310.             if (strpos($param, 'channel://') === false && @file_exists($param)) {
  26311.                 if (isset($options['force'])) {
  26312.                     $otherpackages[] = $param;
  26313.                     continue;
  26314.                 }
  26315.                 $pkg = new PEAR_PackageFile($this->config);
  26316.                 $pf = $pkg->fromAnyFile($param, PEAR_VALIDATE_DOWNLOADING);
  26317.                 if (PEAR::isError($pf)) {
  26318.                     $otherpackages[] = $param;
  26319.                     continue;
  26320.                 }
  26321.                 if ($reg->packageExists($pf->getPackage(), $pf->getChannel()) &&
  26322.                       version_compare($pf->getVersion(),
  26323.                       $reg->packageInfo($pf->getPackage(), 'version', $pf->getChannel()),
  26324.                       '<=')) {
  26325.                     if ($this->config->get('verbose')) {
  26326.                         $this->ui->outputData('Ignoring installed package ' .
  26327.                             $reg->parsedPackageNameToString(
  26328.                             array('package' => $pf->getPackage(),
  26329.                                   'channel' => $pf->getChannel()), true));
  26330.                     }
  26331.                     continue;
  26332.                 }
  26333.                 $otherpackages[] = $param;
  26334.                 continue;
  26335.             }
  26336.             $e = $reg->parsePackageName($param, $this->config->get('default_channel'));
  26337.             if (PEAR::isError($e)) {
  26338.                 $otherpackages[] = $param;
  26339.             } else {
  26340.                 $abstractpackages[] = $e;
  26341.             }
  26342.         }
  26343.         PEAR::staticPopErrorHandling();
  26344.  
  26345.         // if there are any local package .tgz or remote static url, we can't
  26346.         // filter.  The filter only works for abstract packages
  26347.         if (count($abstractpackages) && !isset($options['force'])) {
  26348.             // when not being forced, only do necessary upgrades/installs
  26349.             if (isset($options['upgrade'])) {
  26350.                 $abstractpackages = $this->_filterUptodatePackages($abstractpackages,
  26351.                     $command);
  26352.             } else {
  26353.                 foreach ($abstractpackages as $i => $package) {
  26354.                     if (isset($package['group'])) {
  26355.                         // do not filter out install groups
  26356.                         continue;
  26357.                     }
  26358.                     if ($instreg->packageExists($package['package'], $package['channel'])) {
  26359.                         if ($this->config->get('verbose')) {
  26360.                             $this->ui->outputData('Ignoring installed package ' .
  26361.                                 $reg->parsedPackageNameToString($package, true));
  26362.                         }
  26363.                         unset($abstractpackages[$i]);
  26364.                     }
  26365.                 }
  26366.             }
  26367.             $abstractpackages =
  26368.                 array_map(array($reg, 'parsedPackageNameToString'), $abstractpackages);
  26369.         } elseif (count($abstractpackages)) {
  26370.             $abstractpackages =
  26371.                 array_map(array($reg, 'parsedPackageNameToString'), $abstractpackages);
  26372.         }
  26373.  
  26374.  
  26375.         $packages = array_merge($abstractpackages, $otherpackages);
  26376.         if (!count($packages)) {
  26377.             $this->ui->outputData('Nothing to ' . $command);
  26378.             return true;
  26379.         }
  26380.  
  26381.         $this->downloader = &$this->getDownloader($this->ui, $options, $this->config);
  26382.         $errors = array();
  26383.         $binaries = array();
  26384.         $downloaded = array();
  26385.         $downloaded = &$this->downloader->download($packages);
  26386.         if (PEAR::isError($downloaded)) {
  26387.             return $this->raiseError($downloaded);
  26388.         }
  26389.         $errors = $this->downloader->getErrorMsgs();
  26390.         if (count($errors)) {
  26391.             $err = array();
  26392.             $err['data'] = array();
  26393.             foreach ($errors as $error) {
  26394.                 $err['data'][] = array($error);
  26395.             }
  26396.             $err['headline'] = 'Install Errors';
  26397.             $this->ui->outputData($err);
  26398.             if (!count($downloaded)) {
  26399.                 return $this->raiseError("$command failed");
  26400.             }
  26401.         }
  26402.         $data = array(
  26403.             'headline' => 'Packages that would be Installed'
  26404.         );
  26405.         if (isset($options['pretend'])) {
  26406.             foreach ($downloaded as $package) {
  26407.                 $data['data'][] = array($reg->parsedPackageNameToString($package->getParsedPackage()));
  26408.             }
  26409.             $this->ui->outputData($data, 'pretend');
  26410.             return true;
  26411.         }
  26412.         $this->installer->setOptions($options);
  26413.         $this->installer->sortPackagesForInstall($downloaded);
  26414.         if (PEAR::isError($err = $this->installer->setDownloadedPackages($downloaded))) {
  26415.             $this->raiseError($err->getMessage());
  26416.             return true;
  26417.         }
  26418.         $extrainfo = array();
  26419.         $binaries = array();
  26420.         foreach ($downloaded as $param) {
  26421.             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  26422.             $info = $this->installer->install($param, $options);
  26423.             PEAR::staticPopErrorHandling();
  26424.             if (PEAR::isError($info)) {
  26425.                 $oldinfo = $info;
  26426.                 $pkg = &$param->getPackageFile();
  26427.                 if ($info->getCode() != PEAR_INSTALLER_NOBINARY) {
  26428.                     if (!($info = $pkg->installBinary($this->installer))) {
  26429.                         $this->ui->outputData('ERROR: ' .$oldinfo->getMessage());
  26430.                         continue;
  26431.                     }
  26432.                     // we just installed a different package than requested,
  26433.                     // let's change the param and info so that the rest of this works
  26434.                     $param = $info[0];
  26435.                     $info = $info[1];
  26436.                 }
  26437.             }
  26438.             if (is_array($info)) {
  26439.                 if ($param->getPackageType() == 'extsrc' ||
  26440.                       $param->getPackageType() == 'extbin' ||
  26441.                       $param->getPackageType() == 'zendextsrc' ||
  26442.                       $param->getPackageType() == 'zendextbin') {
  26443.                     $pkg = &$param->getPackageFile();
  26444.                     if ($instbin = $pkg->getInstalledBinary()) {
  26445.                         $instpkg = &$instreg->getPackage($instbin, $pkg->getChannel());
  26446.                     } else {
  26447.                         $instpkg = &$instreg->getPackage($pkg->getPackage(), $pkg->getChannel());
  26448.                     }
  26449.  
  26450.                     foreach ($instpkg->getFilelist() as $name => $atts) {
  26451.                         $pinfo = pathinfo($atts['installed_as']);
  26452.                         if (!isset($pinfo['extension']) ||
  26453.                               in_array($pinfo['extension'], array('c', 'h'))) {
  26454.                             continue; // make sure we don't match php_blah.h
  26455.                         }
  26456.                         if ((strpos($pinfo['basename'], 'php_') === 0 &&
  26457.                               $pinfo['extension'] == 'dll') ||
  26458.                               // most unices
  26459.                               $pinfo['extension'] == 'so' ||
  26460.                               // hp-ux
  26461.                               $pinfo['extension'] == 'sl') {
  26462.                             $binaries[] = array($atts['installed_as'], $pinfo);
  26463.                             break;
  26464.                         }
  26465.                     }
  26466.                     if (count($binaries)) {
  26467.                         foreach ($binaries as $pinfo) {
  26468.                             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  26469.                             $ret = $this->enableExtension(array($pinfo[0]), $param->getPackageType());
  26470.                             PEAR::staticPopErrorHandling();
  26471.                             if (PEAR::isError($ret)) {
  26472.                                 $extrainfo[] = $ret->getMessage();
  26473.                                 if ($param->getPackageType() == 'extsrc' ||
  26474.                                       $param->getPackageType() == 'extbin') {
  26475.                                     $exttype = 'extension';
  26476.                                 } else {
  26477.                                     ob_start();
  26478.                                     phpinfo(INFO_GENERAL);
  26479.                                     $info = ob_get_contents();
  26480.                                     ob_end_clean();
  26481.                                     $debug = function_exists('leak') ? '_debug' : '';
  26482.                                     $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : '';
  26483.                                     $exttype = 'zend_extension' . $debug . $ts;
  26484.                                 }
  26485.                                 $extrainfo[] = 'You should add "' . $exttype . '=' .
  26486.                                     $pinfo[1]['basename'] . '" to php.ini';
  26487.                             } else {
  26488.                                 $extrainfo[] = 'Extension ' . $instpkg->getProvidesExtension() .
  26489.                                     ' enabled in php.ini';
  26490.                             }
  26491.                         }
  26492.                     }
  26493.                 }
  26494.                 if ($this->config->get('verbose') > 0) {
  26495.                     $channel = $param->getChannel();
  26496.                     $label = $reg->parsedPackageNameToString(
  26497.                         array(
  26498.                             'channel' => $channel,
  26499.                             'package' => $param->getPackage(),
  26500.                             'version' => $param->getVersion(),
  26501.                         ));
  26502.                     $out = array('data' => "$command ok: $label");
  26503.                     if (isset($info['release_warnings'])) {
  26504.                         $out['release_warnings'] = $info['release_warnings'];
  26505.                     }
  26506.                     $this->ui->outputData($out, $command);
  26507.                     if (!isset($options['register-only']) && !isset($options['offline'])) {
  26508.                         if ($this->config->isDefinedLayer('ftp')) {
  26509.                             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  26510.                             $info = $this->installer->ftpInstall($param);
  26511.                             PEAR::staticPopErrorHandling();
  26512.                             if (PEAR::isError($info)) {
  26513.                                 $this->ui->outputData($info->getMessage());
  26514.                                 $this->ui->outputData("remote install failed: $label");
  26515.                             } else {
  26516.                                 $this->ui->outputData("remote install ok: $label");
  26517.                             }
  26518.                         }
  26519.                     }
  26520.                 }
  26521.                 $deps = $param->getDeps();
  26522.                 if ($deps) {
  26523.                     if (isset($deps['group'])) {
  26524.                         $groups = $deps['group'];
  26525.                         if (!isset($groups[0])) {
  26526.                             $groups = array($groups);
  26527.                         }
  26528.                         foreach ($groups as $group) {
  26529.                             if ($group['attribs']['name'] == 'default') {
  26530.                                 // default group is always installed, unless the user
  26531.                                 // explicitly chooses to install another group
  26532.                                 continue;
  26533.                             }
  26534.                             $extrainfo[] = $param->getPackage() . ': Optional feature ' .
  26535.                                 $group['attribs']['name'] . ' available (' .
  26536.                                 $group['attribs']['hint'] . ')';
  26537.                         }
  26538.                         $extrainfo[] = $param->getPackage() .
  26539.                             ': To install optional features use "pear install ' .
  26540.                             $reg->parsedPackageNameToString(
  26541.                                 array('package' => $param->getPackage(),
  26542.                                       'channel' => $param->getChannel()), true) .
  26543.                                   '#featurename"';
  26544.                     }
  26545.                 }
  26546.                 $pkg = &$instreg->getPackage($param->getPackage(), $param->getChannel());
  26547.                 // $pkg may be NULL if install is a 'fake' install via --packagingroot
  26548.                 if (is_object($pkg)) {
  26549.                     $pkg->setConfig($this->config);
  26550.                     if ($list = $pkg->listPostinstallScripts()) {
  26551.                         $pn = $reg->parsedPackageNameToString(array('channel' =>
  26552.                            $param->getChannel(), 'package' => $param->getPackage()), true);
  26553.                         $extrainfo[] = $pn . ' has post-install scripts:';
  26554.                         foreach ($list as $file) {
  26555.                             $extrainfo[] = $file;
  26556.                         }
  26557.                         $extrainfo[] = $param->getPackage() .
  26558.                             ': Use "pear run-scripts ' . $pn . '" to finish setup.';
  26559.                         $extrainfo[] = 'DO NOT RUN SCRIPTS FROM UNTRUSTED SOURCES';
  26560.                     }
  26561.                 }
  26562.             } else {
  26563.                 return $this->raiseError("$command failed");
  26564.             }
  26565.         }
  26566.         if (count($extrainfo)) {
  26567.             foreach ($extrainfo as $info) {
  26568.                 $this->ui->outputData($info);
  26569.             }
  26570.         }
  26571.         return true;
  26572.     }
  26573.  
  26574.     // }}}
  26575.     // {{{ doUpgradeAll()
  26576.  
  26577.     function doUpgradeAll($command, $options, $params)
  26578.     {
  26579.         $reg = &$this->config->getRegistry();
  26580.         $toUpgrade = array();
  26581.         foreach ($reg->listChannels() as $channel) {
  26582.             if ($channel == '__uri') {
  26583.                 continue;
  26584.             }
  26585.  
  26586.             // parse name with channel
  26587.             foreach ($reg->listPackages($channel) as $name) {
  26588.                 $toUpgrade[] = $reg->parsedPackageNameToString(array(
  26589.                         'channel' => $channel,
  26590.                         'package' => $name
  26591.                     ));
  26592.             }
  26593.         }
  26594.  
  26595.         $err = $this->doInstall('upgrade-all', $options, $toUpgrade);
  26596.         if (PEAR::isError($err)) {
  26597.             $this->ui->outputData($err->getMessage(), $command);
  26598.         }
  26599.    }
  26600.  
  26601.     // }}}
  26602.     // {{{ doUninstall()
  26603.  
  26604.     function doUninstall($command, $options, $params)
  26605.     {
  26606.         if (empty($this->installer)) {
  26607.             $this->installer = &$this->getInstaller($this->ui);
  26608.         }
  26609.         if (isset($options['remoteconfig'])) {
  26610.             $e = $this->config->readFTPConfigFile($options['remoteconfig']);
  26611.             if (!PEAR::isError($e)) {
  26612.                 $this->installer->setConfig($this->config);
  26613.             }
  26614.         }
  26615.         if (sizeof($params) < 1) {
  26616.             return $this->raiseError("Please supply the package(s) you want to uninstall");
  26617.         }
  26618.         $reg = &$this->config->getRegistry();
  26619.         $newparams = array();
  26620.         $binaries = array();
  26621.         $badparams = array();
  26622.         foreach ($params as $pkg) {
  26623.             $channel = $this->config->get('default_channel');
  26624.             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  26625.             $parsed = $reg->parsePackageName($pkg, $channel);
  26626.             PEAR::staticPopErrorHandling();
  26627.             if (!$parsed || PEAR::isError($parsed)) {
  26628.                 $badparams[] = $pkg;
  26629.                 continue;
  26630.             }
  26631.             $package = $parsed['package'];
  26632.             $channel = $parsed['channel'];
  26633.             $info = &$reg->getPackage($package, $channel);
  26634.             if ($info === null &&
  26635.                  ($channel == 'pear.php.net' || $channel == 'pecl.php.net')) {
  26636.                 // make sure this isn't a package that has flipped from pear to pecl but
  26637.                 // used a package.xml 1.0
  26638.                 $testc = ($channel == 'pear.php.net') ? 'pecl.php.net' : 'pear.php.net';
  26639.                 $info = &$reg->getPackage($package, $testc);
  26640.                 if ($info !== null) {
  26641.                     $channel = $testc;
  26642.                 }
  26643.             }
  26644.             if ($info === null) {
  26645.                 $badparams[] = $pkg;
  26646.             } else {
  26647.                 $newparams[] = &$info;
  26648.                 // check for binary packages (this is an alias for those packages if so)
  26649.                 if ($installedbinary = $info->getInstalledBinary()) {
  26650.                     $this->ui->log('adding binary package ' .
  26651.                         $reg->parsedPackageNameToString(array('channel' => $channel,
  26652.                             'package' => $installedbinary), true));
  26653.                     $newparams[] = &$reg->getPackage($installedbinary, $channel);
  26654.                 }
  26655.                 // add the contents of a dependency group to the list of installed packages
  26656.                 if (isset($parsed['group'])) {
  26657.                     $group = $info->getDependencyGroup($parsed['group']);
  26658.                     if ($group) {
  26659.                         $installed = &$reg->getInstalledGroup($group);
  26660.                         if ($installed) {
  26661.                             foreach ($installed as $i => $p) {
  26662.                                 $newparams[] = &$installed[$i];
  26663.                             }
  26664.                         }
  26665.                     }
  26666.                 }
  26667.             }
  26668.         }
  26669.         $err = $this->installer->sortPackagesForUninstall($newparams);
  26670.         if (PEAR::isError($err)) {
  26671.             $this->ui->outputData($err->getMessage(), $command);
  26672.             return true;
  26673.         }
  26674.         $params = $newparams;
  26675.         // twist this to use it to check on whether dependent packages are also being uninstalled
  26676.         // for circular dependencies like subpackages
  26677.         $this->installer->setUninstallPackages($newparams);
  26678.         $params = array_merge($params, $badparams);
  26679.         $binaries = array();
  26680.         foreach ($params as $pkg) {
  26681.             $this->installer->pushErrorHandling(PEAR_ERROR_RETURN);
  26682.             if ($err = $this->installer->uninstall($pkg, $options)) {
  26683.                 $this->installer->popErrorHandling();
  26684.                 if (PEAR::isError($err)) {
  26685.                     $this->ui->outputData($err->getMessage(), $command);
  26686.                     continue;
  26687.                 }
  26688.                 if ($pkg->getPackageType() == 'extsrc' ||
  26689.                       $pkg->getPackageType() == 'extbin' ||
  26690.                       $pkg->getPackageType() == 'zendextsrc' ||
  26691.                       $pkg->getPackageType() == 'zendextbin') {
  26692.                     if ($instbin = $pkg->getInstalledBinary()) {
  26693.                         continue; // this will be uninstalled later
  26694.                     }
  26695.  
  26696.                     foreach ($pkg->getFilelist() as $name => $atts) {
  26697.                         $pinfo = pathinfo($atts['installed_as']);
  26698.                         if (!isset($pinfo['extension']) ||
  26699.                               in_array($pinfo['extension'], array('c', 'h'))) {
  26700.                             continue; // make sure we don't match php_blah.h
  26701.                         }
  26702.                         if ((strpos($pinfo['basename'], 'php_') === 0 &&
  26703.                               $pinfo['extension'] == 'dll') ||
  26704.                               // most unices
  26705.                               $pinfo['extension'] == 'so' ||
  26706.                               // hp-ux
  26707.                               $pinfo['extension'] == 'sl') {
  26708.                             $binaries[] = array($atts['installed_as'], $pinfo);
  26709.                             break;
  26710.                         }
  26711.                     }
  26712.                     if (count($binaries)) {
  26713.                         foreach ($binaries as $pinfo) {
  26714.                             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  26715.                             $ret = $this->disableExtension(array($pinfo[0]), $pkg->getPackageType());
  26716.                             PEAR::staticPopErrorHandling();
  26717.                             if (PEAR::isError($ret)) {
  26718.                                 $extrainfo[] = $ret->getMessage();
  26719.                                 if ($pkg->getPackageType() == 'extsrc' ||
  26720.                                       $pkg->getPackageType() == 'extbin') {
  26721.                                     $exttype = 'extension';
  26722.                                 } else {
  26723.                                     ob_start();
  26724.                                     phpinfo(INFO_GENERAL);
  26725.                                     $info = ob_get_contents();
  26726.                                     ob_end_clean();
  26727.                                     $debug = function_exists('leak') ? '_debug' : '';
  26728.                                     $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : '';
  26729.                                     $exttype = 'zend_extension' . $debug . $ts;
  26730.                                 }
  26731.                                 $this->ui->outputData('Unable to remove "' . $exttype . '=' .
  26732.                                     $pinfo[1]['basename'] . '" from php.ini', $command);
  26733.                             } else {
  26734.                                 $this->ui->outputData('Extension ' . $pkg->getProvidesExtension() .
  26735.                                     ' disabled in php.ini', $command);
  26736.                             }
  26737.                         }
  26738.                     }
  26739.                 }
  26740.                 $savepkg = $pkg;
  26741.                 if ($this->config->get('verbose') > 0) {
  26742.                     if (is_object($pkg)) {
  26743.                         $pkg = $reg->parsedPackageNameToString($pkg);
  26744.                     }
  26745.                     $this->ui->outputData("uninstall ok: $pkg", $command);
  26746.                 }
  26747.                 if (!isset($options['offline']) && is_object($savepkg) &&
  26748.                       defined('PEAR_REMOTEINSTALL_OK')) {
  26749.                     if ($this->config->isDefinedLayer('ftp')) {
  26750.                         $this->installer->pushErrorHandling(PEAR_ERROR_RETURN);
  26751.                         $info = $this->installer->ftpUninstall($savepkg);
  26752.                         $this->installer->popErrorHandling();
  26753.                         if (PEAR::isError($info)) {
  26754.                             $this->ui->outputData($info->getMessage());
  26755.                             $this->ui->outputData("remote uninstall failed: $pkg");
  26756.                         } else {
  26757.                             $this->ui->outputData("remote uninstall ok: $pkg");
  26758.                         }
  26759.                     }
  26760.                 }
  26761.             } else {
  26762.                 $this->installer->popErrorHandling();
  26763.                 if (is_object($pkg)) {
  26764.                     $pkg = $reg->parsedPackageNameToString($pkg);
  26765.                 }
  26766.                 return $this->raiseError("uninstall failed: $pkg");
  26767.             }
  26768.         }
  26769.         return true;
  26770.     }
  26771.  
  26772.     // }}}
  26773.  
  26774.  
  26775.     // }}}
  26776.     // {{{ doBundle()
  26777.     /*
  26778.     (cox) It just downloads and untars the package, does not do
  26779.             any check that the PEAR_Installer::_installFile() does.
  26780.     */
  26781.  
  26782.     function doBundle($command, $options, $params)
  26783.     {
  26784.         $downloader = &$this->getDownloader($this->ui, array('force' => true, 'nodeps' => true,
  26785.             'soft' => true, 'downloadonly' => true), $this->config);
  26786.         $reg = &$this->config->getRegistry();
  26787.         if (sizeof($params) < 1) {
  26788.             return $this->raiseError("Please supply the package you want to bundle");
  26789.         }
  26790.  
  26791.         if (isset($options['destination'])) {
  26792.             if (!is_dir($options['destination'])) {
  26793.                 System::mkdir('-p ' . $options['destination']);
  26794.             }
  26795.             $dest = realpath($options['destination']);
  26796.         } else {
  26797.             $pwd = getcwd();
  26798.             if (is_dir($pwd . DIRECTORY_SEPARATOR . 'ext')) {
  26799.                 $dest = $pwd . DIRECTORY_SEPARATOR . 'ext';
  26800.             } else {
  26801.                 $dest = $pwd;
  26802.             }
  26803.         }
  26804.         PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  26805.         $err = $downloader->setDownloadDir($dest);
  26806.         PEAR::staticPopErrorHandling();
  26807.         if (PEAR::isError($err)) {
  26808.             return PEAR::raiseError('download directory "' . $dest .
  26809.                 '" is not writeable.');
  26810.         }
  26811.         $result = &$downloader->download(array($params[0]));
  26812.         if (PEAR::isError($result)) {
  26813.             return $result;
  26814.         }
  26815.         if (!isset($result[0])) {
  26816.             return $this->raiseError('unable to unpack ' . $params[0]);
  26817.         }
  26818.         $pkgfile = &$result[0]->getPackageFile();
  26819.         $pkgname = $pkgfile->getName();
  26820.         $pkgversion = $pkgfile->getVersion();
  26821.  
  26822.         // Unpacking -------------------------------------------------
  26823.         $dest .= DIRECTORY_SEPARATOR . $pkgname;
  26824.         $orig = $pkgname . '-' . $pkgversion;
  26825.  
  26826.         $tar = &new Archive_Tar($pkgfile->getArchiveFile());
  26827.         if (!$tar->extractModify($dest, $orig)) {
  26828.             return $this->raiseError('unable to unpack ' . $pkgfile->getArchiveFile());
  26829.         }
  26830.         $this->ui->outputData("Package ready at '$dest'");
  26831.     // }}}
  26832.     }
  26833.  
  26834.     // }}}
  26835.  
  26836.     function doRunScripts($command, $options, $params)
  26837.     {
  26838.         if (!isset($params[0])) {
  26839.             return $this->raiseError('run-scripts expects 1 parameter: a package name');
  26840.         }
  26841.         $reg = &$this->config->getRegistry();
  26842.         PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  26843.         $parsed = $reg->parsePackageName($params[0], $this->config->get('default_channel'));
  26844.         PEAR::staticPopErrorHandling();
  26845.         if (PEAR::isError($parsed)) {
  26846.             return $this->raiseError($parsed);
  26847.         }
  26848.         $package = &$reg->getPackage($parsed['package'], $parsed['channel']);
  26849.         if (is_object($package)) {
  26850.             $package->setConfig($this->config);
  26851.             $package->runPostinstallScripts();
  26852.         } else {
  26853.             return $this->raiseError('Could not retrieve package "' . $params[0] . '" from registry');
  26854.         }
  26855.         $this->ui->outputData('Install scripts complete', $command);
  26856.         return true;
  26857.     }
  26858.  
  26859.     /**
  26860.      * Given a list of packages, filter out those ones that are already up to date
  26861.      *
  26862.      * @param $packages: packages, in parsed array format !
  26863.      * @return list of packages that can be upgraded
  26864.      */
  26865.     function _filterUptodatePackages($packages, $command)
  26866.     {
  26867.         $reg = &$this->config->getRegistry();
  26868.         $latestReleases = array();
  26869.  
  26870.         $ret = array();
  26871.         foreach($packages as $package) {
  26872.             if (isset($package['group'])) {
  26873.                 $ret[] = $package;
  26874.                 continue;
  26875.             }
  26876.             $channel = $package['channel'];
  26877.             $name = $package['package'];
  26878.  
  26879.             if (!$reg->packageExists($name, $channel)) {
  26880.                 $ret[] = $package;
  26881.                 continue;
  26882.             }
  26883.             if (!isset($latestReleases[$channel])) {
  26884.                 // fill in cache for this channel
  26885.                 $chan = &$reg->getChannel($channel);
  26886.                 if (PEAR::isError($chan)) {
  26887.                     return $this->raiseError($chan);
  26888.                 }
  26889.                 if ($chan->supportsREST($this->config->get('preferred_mirror',
  26890.                                                            null, $channel)) &&
  26891.                       $base = $chan->getBaseURL('REST1.0',
  26892.                                                 $this->config->get('preferred_mirror',
  26893.                                                                    null, $channel)))
  26894.                 {
  26895.                     $dorest = true;
  26896.                 } else {
  26897.                     $dorest = false;
  26898.                     $remote = &$this->config->getRemote($this->config);
  26899.                 }
  26900.                 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  26901.                 if ($dorest) {
  26902.                     $rest = &$this->config->getREST('1.0', array());
  26903.                     $installed = array_flip($reg->listPackages($channel));
  26904.                     $latest = $rest->listLatestUpgrades($base,
  26905.                         $this->config->get('preferred_state', null, $channel), $installed,
  26906.                         $channel, $reg);
  26907.                 } else {
  26908.                     $latest = $remote->call("package.listLatestReleases",
  26909.                         $this->config->get('preferred_state', null, $channel));
  26910.                     unset($remote);
  26911.                 }
  26912.                 PEAR::staticPopErrorHandling();
  26913.                 if (PEAR::isError($latest)) {
  26914.                     $this->ui->outputData('Error getting channel info from ' . $channel .
  26915.                         ': ' . $latest->getMessage());
  26916.                     continue;
  26917.                 }
  26918.  
  26919.                 $latestReleases[$channel] = array_change_key_case($latest);
  26920.             }
  26921.  
  26922.             // check package for latest release
  26923.             if (isset($latestReleases[$channel][strtolower($name)])) {
  26924.                 // if not set, up to date
  26925.                 $inst_version = $reg->packageInfo($name, 'version', $channel);
  26926.                 $channel_version = $latestReleases[$channel][strtolower($name)]['version'];
  26927.                 if (version_compare($channel_version, $inst_version, "le")) {
  26928.                     // installed version is up-to-date
  26929.                     continue;
  26930.                 }
  26931.                 // maintain BC
  26932.                 if ($command == 'upgrade-all') {
  26933.                     $this->ui->outputData(array('data' => 'Will upgrade ' .
  26934.                         $reg->parsedPackageNameToString($package)), $command);
  26935.                 }
  26936.                 $ret[] = $package;
  26937.             }
  26938.         }
  26939.  
  26940.         return $ret;
  26941.     }
  26942.  
  26943. }
  26944. ?>
  26945. PEAR-1.7.1/PEAR/Command/Mirror.xml100644   1750   1750        1151 10755221545  11576 <commands version="1.0">
  26946.  <download-all>
  26947.   <summary>Downloads each available package from the default channel</summary>
  26948.   <function>doDownloadAll</function>
  26949.   <shortcut>da</shortcut>
  26950.   <options>
  26951.    <channel>
  26952.     <shortopt>c</shortopt>
  26953.     <doc>specify a channel other than the default channel</doc>
  26954.     <arg>CHAN</arg>
  26955.    </channel>
  26956.   </options>
  26957.   <doc>
  26958. Requests a list of available packages from the default channel ({config default_channel})
  26959. and downloads them to current working directory.  Note: only
  26960. packages within preferred_state ({config preferred_state}) will be downloaded</doc>
  26961.  </download-all>
  26962. </commands>PEAR-1.7.1/PEAR/Command/Mirror.php100644   1750   1750       12221 10755221545  11605 <?php
  26963. /**
  26964.  * PEAR_Command_Mirror (download-all command)
  26965.  *
  26966.  * PHP versions 4 and 5
  26967.  *
  26968.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  26969.  * that is available through the world-wide-web at the following URI:
  26970.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  26971.  * the PHP License and are unable to obtain it through the web, please
  26972.  * send a note to license@php.net so we can mail you a copy immediately.
  26973.  *
  26974.  * @category   pear
  26975.  * @package    PEAR
  26976.  * @author     Alexander Merz <alexmerz@php.net>
  26977.  * @copyright  1997-2008 The PHP Group
  26978.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  26979.  * @version    CVS: $Id: Mirror.php,v 1.19 2008/01/03 20:26:36 cellog Exp $
  26980.  * @link       http://pear.php.net/package/PEAR
  26981.  * @since      File available since Release 1.2.0
  26982.  */
  26983.  
  26984. /**
  26985.  * base class
  26986.  */
  26987. require_once 'PEAR/Command/Common.php';
  26988.  
  26989. /**
  26990.  * PEAR commands for providing file mirrors
  26991.  *
  26992.  * @category   pear
  26993.  * @package    PEAR
  26994.  * @author     Alexander Merz <alexmerz@php.net>
  26995.  * @copyright  1997-2008 The PHP Group
  26996.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  26997.  * @version    Release: 1.7.1
  26998.  * @link       http://pear.php.net/package/PEAR
  26999.  * @since      Class available since Release 1.2.0
  27000.  */
  27001. class PEAR_Command_Mirror extends PEAR_Command_Common
  27002. {
  27003.     // {{{ properties
  27004.  
  27005.     var $commands = array(
  27006.         'download-all' => array(
  27007.             'summary' => 'Downloads each available package from the default channel',
  27008.             'function' => 'doDownloadAll',
  27009.             'shortcut' => 'da',
  27010.             'options' => array(
  27011.                 'channel' =>
  27012.                     array(
  27013.                     'shortopt' => 'c',
  27014.                     'doc' => 'specify a channel other than the default channel',
  27015.                     'arg' => 'CHAN',
  27016.                     ),
  27017.                 ),
  27018.             'doc' => '
  27019. Requests a list of available packages from the default channel ({config default_channel})
  27020. and downloads them to current working directory.  Note: only
  27021. packages within preferred_state ({config preferred_state}) will be downloaded'
  27022.             ),
  27023.         );
  27024.  
  27025.     // }}}
  27026.  
  27027.     // {{{ constructor
  27028.  
  27029.     /**
  27030.      * PEAR_Command_Mirror constructor.
  27031.      *
  27032.      * @access public
  27033.      * @param object PEAR_Frontend a reference to an frontend
  27034.      * @param object PEAR_Config a reference to the configuration data
  27035.      */
  27036.     function PEAR_Command_Mirror(&$ui, &$config)
  27037.     {
  27038.         parent::PEAR_Command_Common($ui, $config);
  27039.     }
  27040.  
  27041.     // }}}
  27042.  
  27043.     /**
  27044.      * For unit-testing
  27045.      */
  27046.     function &factory($a)
  27047.     {
  27048.         $a = &PEAR_Command::factory($a, $this->config);
  27049.         return $a;
  27050.     }
  27051.  
  27052.     // {{{ doDownloadAll()
  27053.     /**
  27054.     * retrieves a list of avaible Packages from master server
  27055.     * and downloads them
  27056.     *
  27057.     * @access public
  27058.     * @param string $command the command
  27059.     * @param array $options the command options before the command
  27060.     * @param array $params the stuff after the command name
  27061.     * @return bool true if succesful
  27062.     * @throw PEAR_Error 
  27063.     */
  27064.     function doDownloadAll($command, $options, $params)
  27065.     {
  27066.         $savechannel = $this->config->get('default_channel');
  27067.         $reg = &$this->config->getRegistry();
  27068.         $channel = isset($options['channel']) ? $options['channel'] :
  27069.             $this->config->get('default_channel');
  27070.         if (!$reg->channelExists($channel)) {
  27071.             $this->config->set('default_channel', $savechannel);
  27072.             return $this->raiseError('Channel "' . $channel . '" does not exist');
  27073.         }
  27074.         $this->config->set('default_channel', $channel);
  27075.         $this->ui->outputData('Using Channel ' . $this->config->get('default_channel'));
  27076.         $chan = $reg->getChannel($channel);
  27077.         if (PEAR::isError($chan)) {
  27078.             return $this->raiseError($chan);
  27079.         }
  27080.         if ($chan->supportsREST($this->config->get('preferred_mirror')) &&
  27081.               $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) {
  27082.             $rest = &$this->config->getREST('1.0', array());
  27083.             $remoteInfo = array_flip($rest->listPackages($base));
  27084.         } else {
  27085.             $remote = &$this->config->getRemote();
  27086.             $stable = ($this->config->get('preferred_state') == 'stable');
  27087.             $remoteInfo = $remote->call("package.listAll", true, $stable, false);
  27088.         }
  27089.         if (PEAR::isError($remoteInfo)) {
  27090.             return $remoteInfo;
  27091.         }
  27092.         $cmd = &$this->factory("download");
  27093.         if (PEAR::isError($cmd)) {
  27094.             return $cmd;
  27095.         }
  27096.         $this->ui->outputData('Using Preferred State of ' .
  27097.             $this->config->get('preferred_state'));
  27098.         $this->ui->outputData('Gathering release information, please wait...');
  27099.         /**
  27100.          * Error handling not necessary, because already done by 
  27101.          * the download command
  27102.          */
  27103.         PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  27104.         $err = $cmd->run('download', array('downloadonly' => true), array_keys($remoteInfo));
  27105.         PEAR::staticPopErrorHandling();
  27106.         $this->config->set('default_channel', $savechannel);
  27107.         if (PEAR::isError($err)) {
  27108.             $this->ui->outputData($err->getMessage());
  27109.         }
  27110.         return true;
  27111.     }
  27112.  
  27113.     // }}}
  27114. }
  27115. PEAR-1.7.1/PEAR/Command/Package.xml100644   1750   1750       13206 10755221545  11703 <commands version="1.0">
  27116.  <package>
  27117.   <summary>Build Package</summary>
  27118.   <function>doPackage</function>
  27119.   <shortcut>p</shortcut>
  27120.   <options>
  27121.    <nocompress>
  27122.     <shortopt>Z</shortopt>
  27123.     <doc>Do not gzip the package file</doc>
  27124.    </nocompress>
  27125.    <showname>
  27126.     <shortopt>n</shortopt>
  27127.     <doc>Print the name of the packaged file.</doc>
  27128.    </showname>
  27129.   </options>
  27130.   <doc>[descfile] [descfile2]
  27131. Creates a PEAR package from its description file (usually called
  27132. package.xml).  If a second packagefile is passed in, then
  27133. the packager will check to make sure that one is a package.xml
  27134. version 1.0, and the other is a package.xml version 2.0.  The
  27135. package.xml version 1.0 will be saved as "package.xml" in the archive,
  27136. and the other as "package2.xml" in the archive"
  27137. </doc>
  27138.  </package>
  27139.  <package-validate>
  27140.   <summary>Validate Package Consistency</summary>
  27141.   <function>doPackageValidate</function>
  27142.   <shortcut>pv</shortcut>
  27143.   <options />
  27144.   <doc>
  27145. </doc>
  27146.  </package-validate>
  27147.  <cvsdiff>
  27148.   <summary>Run a "cvs diff" for all files in a package</summary>
  27149.   <function>doCvsDiff</function>
  27150.   <shortcut>cd</shortcut>
  27151.   <options>
  27152.    <quiet>
  27153.     <shortopt>q</shortopt>
  27154.     <doc>Be quiet</doc>
  27155.    </quiet>
  27156.    <reallyquiet>
  27157.     <shortopt>Q</shortopt>
  27158.     <doc>Be really quiet</doc>
  27159.    </reallyquiet>
  27160.    <date>
  27161.     <shortopt>D</shortopt>
  27162.     <doc>Diff against revision of DATE</doc>
  27163.     <arg>DATE</arg>
  27164.    </date>
  27165.    <release>
  27166.     <shortopt>R</shortopt>
  27167.     <doc>Diff against tag for package release REL</doc>
  27168.     <arg>REL</arg>
  27169.    </release>
  27170.    <revision>
  27171.     <shortopt>r</shortopt>
  27172.     <doc>Diff against revision REV</doc>
  27173.     <arg>REV</arg>
  27174.    </revision>
  27175.    <context>
  27176.     <shortopt>c</shortopt>
  27177.     <doc>Generate context diff</doc>
  27178.    </context>
  27179.    <unified>
  27180.     <shortopt>u</shortopt>
  27181.     <doc>Generate unified diff</doc>
  27182.    </unified>
  27183.    <ignore-case>
  27184.     <shortopt>i</shortopt>
  27185.     <doc>Ignore case, consider upper- and lower-case letters equivalent</doc>
  27186.    </ignore-case>
  27187.    <ignore-whitespace>
  27188.     <shortopt>b</shortopt>
  27189.     <doc>Ignore changes in amount of white space</doc>
  27190.    </ignore-whitespace>
  27191.    <ignore-blank-lines>
  27192.     <shortopt>B</shortopt>
  27193.     <doc>Ignore changes that insert or delete blank lines</doc>
  27194.    </ignore-blank-lines>
  27195.    <brief>
  27196.     <doc>Report only whether the files differ, no details</doc>
  27197.    </brief>
  27198.    <dry-run>
  27199.     <shortopt>n</shortopt>
  27200.     <doc>Don't do anything, just pretend</doc>
  27201.    </dry-run>
  27202.   </options>
  27203.   <doc><package.xml>
  27204. Compares all the files in a package.  Without any options, this
  27205. command will compare the current code with the last checked-in code.
  27206. Using the -r or -R option you may compare the current code with that
  27207. of a specific release.
  27208. </doc>
  27209.  </cvsdiff>
  27210.  <cvstag>
  27211.   <summary>Set CVS Release Tag</summary>
  27212.   <function>doCvsTag</function>
  27213.   <shortcut>ct</shortcut>
  27214.   <options>
  27215.    <quiet>
  27216.     <shortopt>q</shortopt>
  27217.     <doc>Be quiet</doc>
  27218.    </quiet>
  27219.    <reallyquiet>
  27220.     <shortopt>Q</shortopt>
  27221.     <doc>Be really quiet</doc>
  27222.    </reallyquiet>
  27223.    <slide>
  27224.     <shortopt>F</shortopt>
  27225.     <doc>Move (slide) tag if it exists</doc>
  27226.    </slide>
  27227.    <delete>
  27228.     <shortopt>d</shortopt>
  27229.     <doc>Remove tag</doc>
  27230.    </delete>
  27231.    <dry-run>
  27232.     <shortopt>n</shortopt>
  27233.     <doc>Don't do anything, just pretend</doc>
  27234.    </dry-run>
  27235.   </options>
  27236.   <doc><package.xml>
  27237. Sets a CVS tag on all files in a package.  Use this command after you have
  27238. packaged a distribution tarball with the "package" command to tag what
  27239. revisions of what files were in that release.  If need to fix something
  27240. after running cvstag once, but before the tarball is released to the public,
  27241. use the "slide" option to move the release tag.
  27242. </doc>
  27243.  </cvstag>
  27244.  <package-dependencies>
  27245.   <summary>Show package dependencies</summary>
  27246.   <function>doPackageDependencies</function>
  27247.   <shortcut>pd</shortcut>
  27248.   <options />
  27249.   <doc>
  27250. List all dependencies the package has.</doc>
  27251.  </package-dependencies>
  27252.  <sign>
  27253.   <summary>Sign a package distribution file</summary>
  27254.   <function>doSign</function>
  27255.   <shortcut>si</shortcut>
  27256.   <options />
  27257.   <doc><package-file>
  27258. Signs a package distribution (.tar or .tgz) file with GnuPG.</doc>
  27259.  </sign>
  27260.  <makerpm>
  27261.   <summary>Builds an RPM spec file from a PEAR package</summary>
  27262.   <function>doMakeRPM</function>
  27263.   <shortcut>rpm</shortcut>
  27264.   <options>
  27265.    <spec-template>
  27266.     <shortopt>t</shortopt>
  27267.     <arg>FILE</arg>
  27268.     <doc>Use FILE as RPM spec file template</doc>
  27269.    </spec-template>
  27270.    <rpm-pkgname>
  27271.     <shortopt>p</shortopt>
  27272.     <arg>FORMAT</arg>
  27273.     <doc>Use FORMAT as format string for RPM package name, %s is replaced
  27274. by the PEAR package name, defaults to "PEAR::%s".</doc>
  27275.    </rpm-pkgname>
  27276.   </options>
  27277.   <doc><package-file>
  27278.  
  27279. Creates an RPM .spec file for wrapping a PEAR package inside an RPM
  27280. package.  Intended to be used from the SPECS directory, with the PEAR
  27281. package tarball in the SOURCES directory:
  27282.  
  27283. $ pear makerpm ../SOURCES/Net_Socket-1.0.tgz
  27284. Wrote RPM spec file PEAR::Net_Geo-1.0.spec
  27285. $ rpm -bb PEAR::Net_Socket-1.0.spec
  27286. ...
  27287. Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm
  27288. </doc>
  27289.  </makerpm>
  27290.  <convert>
  27291.   <summary>Convert a package.xml 1.0 to package.xml 2.0 format</summary>
  27292.   <function>doConvert</function>
  27293.   <shortcut>c2</shortcut>
  27294.   <options>
  27295.    <flat>
  27296.     <shortopt>f</shortopt>
  27297.     <doc>do not beautify the filelist.</doc>
  27298.    </flat>
  27299.   </options>
  27300.   <doc>[descfile] [descfile2]
  27301. Converts a package.xml in 1.0 format into a package.xml
  27302. in 2.0 format.  The new file will be named package2.xml by default,
  27303. and package.xml will be used as the old file by default.
  27304. This is not the most intelligent conversion, and should only be
  27305. used for automated conversion or learning the format.
  27306. </doc>
  27307.  </convert>
  27308. </commands>
  27309. PEAR-1.7.1/PEAR/Command/Package.php100644   1750   1750       75370 10755221545  11704 <?php
  27310. /**
  27311.  * PEAR_Command_Package (package, package-validate, cvsdiff, cvstag, package-dependencies,
  27312.  * sign, makerpm, convert commands)
  27313.  *
  27314.  * PHP versions 4 and 5
  27315.  *
  27316.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  27317.  * that is available through the world-wide-web at the following URI:
  27318.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  27319.  * the PHP License and are unable to obtain it through the web, please
  27320.  * send a note to license@php.net so we can mail you a copy immediately.
  27321.  *
  27322.  * @category   pear
  27323.  * @package    PEAR
  27324.  * @author     Stig Bakken <ssb@php.net>
  27325.  * @author     Martin Jansen <mj@php.net>
  27326.  * @author     Greg Beaver <cellog@php.net>
  27327.  * @copyright  1997-2008 The PHP Group
  27328.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  27329.  * @version    CVS: $Id: Package.php,v 1.126 2008/01/29 03:21:01 cellog Exp $
  27330.  * @link       http://pear.php.net/package/PEAR
  27331.  * @since      File available since Release 0.1
  27332.  */
  27333.  
  27334. /**
  27335.  * base class
  27336.  */
  27337. require_once 'PEAR/Command/Common.php';
  27338.  
  27339. /**
  27340.  * PEAR commands for login/logout
  27341.  *
  27342.  * @category   pear
  27343.  * @package    PEAR
  27344.  * @author     Stig Bakken <ssb@php.net>
  27345.  * @author     Martin Jansen <mj@php.net>
  27346.  * @author     Greg Beaver <cellog@php.net>
  27347.  * @copyright  1997-2008 The PHP Group
  27348.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  27349.  * @version    Release: @package_version@
  27350.  * @link       http://pear.php.net/package/PEAR
  27351.  * @since      Class available since Release 0.1
  27352.  */
  27353.  
  27354. class PEAR_Command_Package extends PEAR_Command_Common
  27355. {
  27356.     // {{{ properties
  27357.  
  27358.     var $commands = array(
  27359.         'package' => array(
  27360.             'summary' => 'Build Package',
  27361.             'function' => 'doPackage',
  27362.             'shortcut' => 'p',
  27363.             'options' => array(
  27364.                 'nocompress' => array(
  27365.                     'shortopt' => 'Z',
  27366.                     'doc' => 'Do not gzip the package file'
  27367.                     ),
  27368.                 'showname' => array(
  27369.                     'shortopt' => 'n',
  27370.                     'doc' => 'Print the name of the packaged file.',
  27371.                     ),
  27372.                 ),
  27373.             'doc' => '[descfile] [descfile2]
  27374. Creates a PEAR package from its description file (usually called
  27375. package.xml).  If a second packagefile is passed in, then
  27376. the packager will check to make sure that one is a package.xml
  27377. version 1.0, and the other is a package.xml version 2.0.  The
  27378. package.xml version 1.0 will be saved as "package.xml" in the archive,
  27379. and the other as "package2.xml" in the archive"
  27380. '
  27381.             ),
  27382.         'package-validate' => array(
  27383.             'summary' => 'Validate Package Consistency',
  27384.             'function' => 'doPackageValidate',
  27385.             'shortcut' => 'pv',
  27386.             'options' => array(),
  27387.             'doc' => '
  27388. ',
  27389.             ),
  27390.         'cvsdiff' => array(
  27391.             'summary' => 'Run a "cvs diff" for all files in a package',
  27392.             'function' => 'doCvsDiff',
  27393.             'shortcut' => 'cd',
  27394.             'options' => array(
  27395.                 'quiet' => array(
  27396.                     'shortopt' => 'q',
  27397.                     'doc' => 'Be quiet',
  27398.                     ),
  27399.                 'reallyquiet' => array(
  27400.                     'shortopt' => 'Q',
  27401.                     'doc' => 'Be really quiet',
  27402.                     ),
  27403.                 'date' => array(
  27404.                     'shortopt' => 'D',
  27405.                     'doc' => 'Diff against revision of DATE',
  27406.                     'arg' => 'DATE',
  27407.                     ),
  27408.                 'release' => array(
  27409.                     'shortopt' => 'R',
  27410.                     'doc' => 'Diff against tag for package release REL',
  27411.                     'arg' => 'REL',
  27412.                     ),
  27413.                 'revision' => array(
  27414.                     'shortopt' => 'r',
  27415.                     'doc' => 'Diff against revision REV',
  27416.                     'arg' => 'REV',
  27417.                     ),
  27418.                 'context' => array(
  27419.                     'shortopt' => 'c',
  27420.                     'doc' => 'Generate context diff',
  27421.                     ),
  27422.                 'unified' => array(
  27423.                     'shortopt' => 'u',
  27424.                     'doc' => 'Generate unified diff',
  27425.                     ),
  27426.                 'ignore-case' => array(
  27427.                     'shortopt' => 'i',
  27428.                     'doc' => 'Ignore case, consider upper- and lower-case letters equivalent',
  27429.                     ),
  27430.                 'ignore-whitespace' => array(
  27431.                     'shortopt' => 'b',
  27432.                     'doc' => 'Ignore changes in amount of white space',
  27433.                     ),
  27434.                 'ignore-blank-lines' => array(
  27435.                     'shortopt' => 'B',
  27436.                     'doc' => 'Ignore changes that insert or delete blank lines',
  27437.                     ),
  27438.                 'brief' => array(
  27439.                     'doc' => 'Report only whether the files differ, no details',
  27440.                     ),
  27441.                 'dry-run' => array(
  27442.                     'shortopt' => 'n',
  27443.                     'doc' => 'Don\'t do anything, just pretend',
  27444.                     ),
  27445.                 ),
  27446.             'doc' => '<package.xml>
  27447. Compares all the files in a package.  Without any options, this
  27448. command will compare the current code with the last checked-in code.
  27449. Using the -r or -R option you may compare the current code with that
  27450. of a specific release.
  27451. ',
  27452.             ),
  27453.         'cvstag' => array(
  27454.             'summary' => 'Set CVS Release Tag',
  27455.             'function' => 'doCvsTag',
  27456.             'shortcut' => 'ct',
  27457.             'options' => array(
  27458.                 'quiet' => array(
  27459.                     'shortopt' => 'q',
  27460.                     'doc' => 'Be quiet',
  27461.                     ),
  27462.                 'reallyquiet' => array(
  27463.                     'shortopt' => 'Q',
  27464.                     'doc' => 'Be really quiet',
  27465.                     ),
  27466.                 'slide' => array(
  27467.                     'shortopt' => 'F',
  27468.                     'doc' => 'Move (slide) tag if it exists',
  27469.                     ),
  27470.                 'delete' => array(
  27471.                     'shortopt' => 'd',
  27472.                     'doc' => 'Remove tag',
  27473.                     ),
  27474.                 'dry-run' => array(
  27475.                     'shortopt' => 'n',
  27476.                     'doc' => 'Don\'t do anything, just pretend',
  27477.                     ),
  27478.                 ),
  27479.             'doc' => '<package.xml> [files...]
  27480. Sets a CVS tag on all files in a package.  Use this command after you have
  27481. packaged a distribution tarball with the "package" command to tag what
  27482. revisions of what files were in that release.  If need to fix something
  27483. after running cvstag once, but before the tarball is released to the public,
  27484. use the "slide" option to move the release tag.
  27485.  
  27486. to include files (such as a second package.xml, or tests not included in the
  27487. release), pass them as additional parameters.
  27488. ',
  27489.             ),
  27490.         'package-dependencies' => array(
  27491.             'summary' => 'Show package dependencies',
  27492.             'function' => 'doPackageDependencies',
  27493.             'shortcut' => 'pd',
  27494.             'options' => array(),
  27495.             'doc' => '
  27496. List all dependencies the package has.'
  27497.             ),
  27498.         'sign' => array(
  27499.             'summary' => 'Sign a package distribution file',
  27500.             'function' => 'doSign',
  27501.             'shortcut' => 'si',
  27502.             'options' => array(
  27503.                 'verbose' => array(
  27504.                     'shortopt' => 'v',
  27505.                     'doc' => 'Display GnuPG output',
  27506.                     ),
  27507.             ),
  27508.             'doc' => '<package-file>
  27509. Signs a package distribution (.tar or .tgz) file with GnuPG.',
  27510.             ),
  27511.         'makerpm' => array(
  27512.             'summary' => 'Builds an RPM spec file from a PEAR package',
  27513.             'function' => 'doMakeRPM',
  27514.             'shortcut' => 'rpm',
  27515.             'options' => array(
  27516.                 'spec-template' => array(
  27517.                     'shortopt' => 't',
  27518.                     'arg' => 'FILE',
  27519.                     'doc' => 'Use FILE as RPM spec file template'
  27520.                     ),
  27521.                 'rpm-pkgname' => array(
  27522.                     'shortopt' => 'p',
  27523.                     'arg' => 'FORMAT',
  27524.                     'doc' => 'Use FORMAT as format string for RPM package name, %s is replaced
  27525. by the PEAR package name, defaults to "PEAR::%s".',
  27526.                     ),
  27527.                 ),
  27528.             'doc' => '<package-file>
  27529.  
  27530. Creates an RPM .spec file for wrapping a PEAR package inside an RPM
  27531. package.  Intended to be used from the SPECS directory, with the PEAR
  27532. package tarball in the SOURCES directory:
  27533.  
  27534. $ pear makerpm ../SOURCES/Net_Socket-1.0.tgz
  27535. Wrote RPM spec file PEAR::Net_Geo-1.0.spec
  27536. $ rpm -bb PEAR::Net_Socket-1.0.spec
  27537. ...
  27538. Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm
  27539. ',
  27540.             ),
  27541.         'convert' => array(
  27542.             'summary' => 'Convert a package.xml 1.0 to package.xml 2.0 format',
  27543.             'function' => 'doConvert',
  27544.             'shortcut' => 'c2',
  27545.             'options' => array(
  27546.                 'flat' => array(
  27547.                     'shortopt' => 'f',
  27548.                     'doc' => 'do not beautify the filelist.',
  27549.                     ),
  27550.                 ),
  27551.             'doc' => '[descfile] [descfile2]
  27552. Converts a package.xml in 1.0 format into a package.xml
  27553. in 2.0 format.  The new file will be named package2.xml by default,
  27554. and package.xml will be used as the old file by default.
  27555. This is not the most intelligent conversion, and should only be
  27556. used for automated conversion or learning the format.
  27557. '
  27558.             ),
  27559.         );
  27560.  
  27561.     var $output;
  27562.  
  27563.     // }}}
  27564.     // {{{ constructor
  27565.  
  27566.     /**
  27567.      * PEAR_Command_Package constructor.
  27568.      *
  27569.      * @access public
  27570.      */
  27571.     function PEAR_Command_Package(&$ui, &$config)
  27572.     {
  27573.         parent::PEAR_Command_Common($ui, $config);
  27574.     }
  27575.  
  27576.     // }}}
  27577.  
  27578.     // {{{ _displayValidationResults()
  27579.  
  27580.     function _displayValidationResults($err, $warn, $strict = false)
  27581.     {
  27582.         foreach ($err as $e) {
  27583.             $this->output .= "Error: $e\n";
  27584.         }
  27585.         foreach ($warn as $w) {
  27586.             $this->output .= "Warning: $w\n";
  27587.         }
  27588.         $this->output .= sprintf('Validation: %d error(s), %d warning(s)'."\n",
  27589.                                        sizeof($err), sizeof($warn));
  27590.         if ($strict && sizeof($err) > 0) {
  27591.             $this->output .= "Fix these errors and try again.";
  27592.             return false;
  27593.         }
  27594.         return true;
  27595.     }
  27596.  
  27597.     // }}}
  27598.     function &getPackager()
  27599.     {
  27600.         if (!class_exists('PEAR_Packager')) {
  27601.             require_once 'PEAR/Packager.php';
  27602.         }
  27603.         $a = &new PEAR_Packager;
  27604.         return $a;
  27605.     }
  27606.  
  27607.     function &getPackageFile($config, $debug = false, $tmpdir = null)
  27608.     {
  27609.         if (!class_exists('PEAR_Common')) {
  27610.             require_once 'PEAR/Common.php';
  27611.         }
  27612.         if (!class_exists('PEAR_PackageFile')) {
  27613.             require_once 'PEAR/PackageFile.php';
  27614.         }
  27615.         $a = &new PEAR_PackageFile($config, $debug, $tmpdir);
  27616.         $common = new PEAR_Common;
  27617.         $common->ui = $this->ui;
  27618.         $a->setLogger($common);
  27619.         return $a;
  27620.     }
  27621.     // {{{ doPackage()
  27622.  
  27623.     function doPackage($command, $options, $params)
  27624.     {
  27625.         $this->output = '';
  27626.         $pkginfofile = isset($params[0]) ? $params[0] : 'package.xml';
  27627.         $pkg2 = isset($params[1]) ? $params[1] : null;
  27628.         if (!$pkg2 && !isset($params[0])) {
  27629.             if (file_exists('package2.xml')) {
  27630.                 $pkg2 = 'package2.xml';
  27631.             }
  27632.         }
  27633.         $packager = &$this->getPackager();
  27634.         $compress = empty($options['nocompress']) ? true : false;
  27635.         $result = $packager->package($pkginfofile, $compress, $pkg2);
  27636.         if (PEAR::isError($result)) {
  27637.             return $this->raiseError($result);
  27638.         }
  27639.         // Don't want output, only the package file name just created
  27640.         if (isset($options['showname'])) {
  27641.             $this->output = $result;
  27642.         }
  27643.         if ($this->output) {
  27644.             $this->ui->outputData($this->output, $command);
  27645.         }
  27646.         return true;
  27647.     }
  27648.  
  27649.     // }}}
  27650.     // {{{ doPackageValidate()
  27651.  
  27652.     function doPackageValidate($command, $options, $params)
  27653.     {
  27654.         $this->output = '';
  27655.         if (sizeof($params) < 1) {
  27656.             $params[0] = "package.xml";
  27657.         }
  27658.         $obj = &$this->getPackageFile($this->config, $this->_debug);
  27659.         $obj->rawReturn();
  27660.         PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  27661.         $info = $obj->fromTgzFile($params[0], PEAR_VALIDATE_NORMAL);
  27662.         if (PEAR::isError($info)) {
  27663.             $info = $obj->fromPackageFile($params[0], PEAR_VALIDATE_NORMAL);
  27664.         } else {
  27665.             $archive = $info->getArchiveFile();
  27666.             $tar = &new Archive_Tar($archive);
  27667.             $tar->extract(dirname($info->getPackageFile()));
  27668.             $info->setPackageFile(dirname($info->getPackageFile()) . DIRECTORY_SEPARATOR .
  27669.                 $info->getPackage() . '-' . $info->getVersion() . DIRECTORY_SEPARATOR .
  27670.                 basename($info->getPackageFile()));
  27671.         }
  27672.         PEAR::staticPopErrorHandling();
  27673.         if (PEAR::isError($info)) {
  27674.             return $this->raiseError($info);
  27675.         }
  27676.         $valid = false;
  27677.         if ($info->getPackagexmlVersion() == '2.0') {
  27678.             if ($valid = $info->validate(PEAR_VALIDATE_NORMAL)) {
  27679.                 $info->flattenFileList();
  27680.                 $valid = $info->validate(PEAR_VALIDATE_PACKAGING);
  27681.             }
  27682.         } else {
  27683.             $valid = $info->validate(PEAR_VALIDATE_PACKAGING);
  27684.         }
  27685.         $err = array();
  27686.         $warn = array();
  27687.         if (!$valid) {
  27688.             foreach ($info->getValidationWarnings() as $error) {
  27689.                 if ($error['level'] == 'warning') {
  27690.                     $warn[] = $error['message'];
  27691.                 } else {
  27692.                     $err[] = $error['message'];
  27693.                 }
  27694.             }
  27695.         }
  27696.         $this->_displayValidationResults($err, $warn);
  27697.         $this->ui->outputData($this->output, $command);
  27698.         return true;
  27699.     }
  27700.  
  27701.     // }}}
  27702.     // {{{ doCvsTag()
  27703.  
  27704.     function doCvsTag($command, $options, $params)
  27705.     {
  27706.         $this->output = '';
  27707.         $_cmd = $command;
  27708.         if (sizeof($params) < 1) {
  27709.             $help = $this->getHelp($command);
  27710.             return $this->raiseError("$command: missing parameter: $help[0]");
  27711.         }
  27712.         $obj = &$this->getPackageFile($this->config, $this->_debug);
  27713.         $info = $obj->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL);
  27714.         if (PEAR::isError($info)) {
  27715.             return $this->raiseError($info);
  27716.         }
  27717.         $err = $warn = array();
  27718.         if (!$info->validate()) {
  27719.             foreach ($info->getValidationWarnings() as $error) {
  27720.                 if ($error['level'] == 'warning') {
  27721.                     $warn[] = $error['message'];
  27722.                 } else {
  27723.                     $err[] = $error['message'];
  27724.                 }
  27725.             }
  27726.         }
  27727.         if (!$this->_displayValidationResults($err, $warn, true)) {
  27728.             $this->ui->outputData($this->output, $command);
  27729.             return $this->raiseError('CVS tag failed');
  27730.         }
  27731.         $version = $info->getVersion();
  27732.         $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $version);
  27733.         $cvstag = "RELEASE_$cvsversion";
  27734.         $files = array_keys($info->getFilelist());
  27735.         $command = "cvs";
  27736.         if (isset($options['quiet'])) {
  27737.             $command .= ' -q';
  27738.         }
  27739.         if (isset($options['reallyquiet'])) {
  27740.             $command .= ' -Q';
  27741.         }
  27742.         $command .= ' tag';
  27743.         if (isset($options['slide'])) {
  27744.             $command .= ' -F';
  27745.         }
  27746.         if (isset($options['delete'])) {
  27747.             $command .= ' -d';
  27748.         }
  27749.         $command .= ' ' . $cvstag . ' ' . escapeshellarg($params[0]);
  27750.         array_shift($params);
  27751.         if (count($params)) {
  27752.             // add in additional files to be tagged
  27753.             $files = array_merge($files, $params);
  27754.         }
  27755.         foreach ($files as $file) {
  27756.             $command .= ' ' . escapeshellarg($file);
  27757.         }
  27758.         if ($this->config->get('verbose') > 1) {
  27759.             $this->output .= "+ $command\n";
  27760.         }
  27761.         $this->output .= "+ $command\n";
  27762.         if (empty($options['dry-run'])) {
  27763.             $fp = popen($command, "r");
  27764.             while ($line = fgets($fp, 1024)) {
  27765.                 $this->output .= rtrim($line)."\n";
  27766.             }
  27767.             pclose($fp);
  27768.         }
  27769.         $this->ui->outputData($this->output, $_cmd);
  27770.         return true;
  27771.     }
  27772.  
  27773.     // }}}
  27774.     // {{{ doCvsDiff()
  27775.  
  27776.     function doCvsDiff($command, $options, $params)
  27777.     {
  27778.         $this->output = '';
  27779.         if (sizeof($params) < 1) {
  27780.             $help = $this->getHelp($command);
  27781.             return $this->raiseError("$command: missing parameter: $help[0]");
  27782.         }
  27783.         $obj = &$this->getPackageFile($this->config, $this->_debug);
  27784.         $info = $obj->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL);
  27785.         if (PEAR::isError($info)) {
  27786.             return $this->raiseError($info);
  27787.         }
  27788.         $err = $warn = array();
  27789.         if (!$info->validate()) {
  27790.             foreach ($info->getValidationWarnings() as $error) {
  27791.                 if ($error['level'] == 'warning') {
  27792.                     $warn[] = $error['message'];
  27793.                 } else {
  27794.                     $err[] = $error['message'];
  27795.                 }
  27796.             }
  27797.         }
  27798.         if (!$this->_displayValidationResults($err, $warn, true)) {
  27799.             $this->ui->outputData($this->output, $command);
  27800.             return $this->raiseError('CVS diff failed');
  27801.         }
  27802.         $info1 = $info->getFilelist();
  27803.         $files = $info1;
  27804.         $cmd = "cvs";
  27805.         if (isset($options['quiet'])) {
  27806.             $cmd .= ' -q';
  27807.             unset($options['quiet']);
  27808.         }
  27809.         if (isset($options['reallyquiet'])) {
  27810.             $cmd .= ' -Q';
  27811.             unset($options['reallyquiet']);
  27812.         }
  27813.         if (isset($options['release'])) {
  27814.             $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $options['release']);
  27815.             $cvstag = "RELEASE_$cvsversion";
  27816.             $options['revision'] = $cvstag;
  27817.             unset($options['release']);
  27818.         }
  27819.         $execute = true;
  27820.         if (isset($options['dry-run'])) {
  27821.             $execute = false;
  27822.             unset($options['dry-run']);
  27823.         }
  27824.         $cmd .= ' diff';
  27825.         // the rest of the options are passed right on to "cvs diff"
  27826.         foreach ($options as $option => $optarg) {
  27827.             $arg = $short = false;
  27828.             if (isset($this->commands[$command]['options'][$option])) {
  27829.                 $arg = $this->commands[$command]['options'][$option]['arg'];
  27830.                 $short = $this->commands[$command]['options'][$option]['shortopt'];
  27831.             }
  27832.             $cmd .= $short ? " -$short" : " --$option";
  27833.             if ($arg && $optarg) {
  27834.                 $cmd .= ($short ? '' : '=') . escapeshellarg($optarg);
  27835.             }
  27836.         }
  27837.         foreach ($files as $file) {
  27838.             $cmd .= ' ' . escapeshellarg($file['name']);
  27839.         }
  27840.         if ($this->config->get('verbose') > 1) {
  27841.             $this->output .= "+ $cmd\n";
  27842.         }
  27843.         if ($execute) {
  27844.             $fp = popen($cmd, "r");
  27845.             while ($line = fgets($fp, 1024)) {
  27846.                 $this->output .= rtrim($line)."\n";
  27847.             }
  27848.             pclose($fp);
  27849.         }
  27850.         $this->ui->outputData($this->output, $command);
  27851.         return true;
  27852.     }
  27853.  
  27854.     // }}}
  27855.     // {{{ doPackageDependencies()
  27856.  
  27857.     function doPackageDependencies($command, $options, $params)
  27858.     {
  27859.         // $params[0] -> the PEAR package to list its information
  27860.         if (sizeof($params) != 1) {
  27861.             return $this->raiseError("bad parameter(s), try \"help $command\"");
  27862.         }
  27863.         $obj = &$this->getPackageFile($this->config, $this->_debug);
  27864.         $info = $obj->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL);
  27865.         if (PEAR::isError($info)) {
  27866.             return $this->raiseError($info);
  27867.         }
  27868.         $deps = $info->getDeps();
  27869.         if (is_array($deps)) {
  27870.             if ($info->getPackagexmlVersion() == '1.0') {
  27871.                 $data = array(
  27872.                     'caption' => 'Dependencies for pear/' . $info->getPackage(),
  27873.                     'border' => true,
  27874.                     'headline' => array("Required?", "Type", "Name", "Relation", "Version"),
  27875.                     );
  27876.  
  27877.                 foreach ($deps as $d) {
  27878.                     if (isset($d['optional'])) {
  27879.                         if ($d['optional'] == 'yes') {
  27880.                             $req = 'No';
  27881.                         } else {
  27882.                             $req = 'Yes';
  27883.                         }
  27884.                     } else {
  27885.                         $req = 'Yes';
  27886.                     }
  27887.                     if (isset($this->_deps_rel_trans[$d['rel']])) {
  27888.                         $rel = $this->_deps_rel_trans[$d['rel']];
  27889.                     } else {
  27890.                         $rel = $d['rel'];
  27891.                     }
  27892.  
  27893.                     if (isset($this->_deps_type_trans[$d['type']])) {
  27894.                         $type = ucfirst($this->_deps_type_trans[$d['type']]);
  27895.                     } else {
  27896.                         $type = $d['type'];
  27897.                     }
  27898.  
  27899.                     if (isset($d['name'])) {
  27900.                         $name = $d['name'];
  27901.                     } else {
  27902.                         $name = '';
  27903.                     }
  27904.  
  27905.                     if (isset($d['version'])) {
  27906.                         $version = $d['version'];
  27907.                     } else {
  27908.                         $version = '';
  27909.                     }
  27910.  
  27911.                     $data['data'][] = array($req, $type, $name, $rel, $version);
  27912.                 }
  27913.             } else { // package.xml 2.0 dependencies display
  27914.                 require_once 'PEAR/Dependency2.php';
  27915.                 $deps = $info->getDependencies();
  27916.                 $reg = &$this->config->getRegistry();
  27917.                 if (is_array($deps)) {
  27918.                     $d = new PEAR_Dependency2($this->config, array(), '');
  27919.                     $data = array(
  27920.                         'caption' => 'Dependencies for ' . $info->getPackage(),
  27921.                         'border' => true,
  27922.                         'headline' => array("Required?", "Type", "Name", 'Versioning', 'Group'),
  27923.                         );
  27924.                     foreach ($deps as $type => $subd) {
  27925.                         $req = ($type == 'required') ? 'Yes' : 'No';
  27926.                         if ($type == 'group') {
  27927.                             $group = $subd['attribs']['name'];
  27928.                         } else {
  27929.                             $group = '';
  27930.                         }
  27931.                         if (!isset($subd[0])) {
  27932.                             $subd = array($subd);
  27933.                         }
  27934.                         foreach ($subd as $groupa) {
  27935.                             foreach ($groupa as $deptype => $depinfo) {
  27936.                                 if ($deptype == 'attribs') {
  27937.                                     continue;
  27938.                                 }
  27939.                                 if ($deptype == 'pearinstaller') {
  27940.                                     $deptype = 'pear Installer';
  27941.                                 }
  27942.                                 if (!isset($depinfo[0])) {
  27943.                                     $depinfo = array($depinfo);
  27944.                                 }
  27945.                                 foreach ($depinfo as $inf) {
  27946.                                     $name = '';
  27947.                                     if (isset($inf['channel'])) {
  27948.                                         $alias = $reg->channelAlias($inf['channel']);
  27949.                                         if (!$alias) {
  27950.                                             $alias = '(channel?) ' .$inf['channel'];
  27951.                                         }
  27952.                                         $name = $alias . '/';
  27953.                                     }
  27954.                                     if (isset($inf['name'])) {
  27955.                                         $name .= $inf['name'];
  27956.                                     } elseif (isset($inf['pattern'])) {
  27957.                                         $name .= $inf['pattern'];
  27958.                                     } else {
  27959.                                         $name .= '';
  27960.                                     }
  27961.                                     if (isset($inf['uri'])) {
  27962.                                         $name .= ' [' . $inf['uri'] .  ']';
  27963.                                     }
  27964.                                     if (isset($inf['conflicts'])) {
  27965.                                         $ver = 'conflicts';
  27966.                                     } else {
  27967.                                         $ver = $d->_getExtraString($inf);
  27968.                                     }
  27969.                                     $data['data'][] = array($req, ucfirst($deptype), $name,
  27970.                                         $ver, $group);
  27971.                                 }
  27972.                             }
  27973.                         }
  27974.                     }
  27975.                 }
  27976.             }
  27977.  
  27978.             $this->ui->outputData($data, $command);
  27979.             return true;
  27980.         }
  27981.  
  27982.         // Fallback
  27983.         $this->ui->outputData("This package does not have any dependencies.", $command);
  27984.     }
  27985.  
  27986.     // }}}
  27987.     // {{{ doSign()
  27988.  
  27989.     function doSign($command, $options, $params)
  27990.     {
  27991.         require_once 'System.php';
  27992.         require_once 'Archive/Tar.php';
  27993.         // should move most of this code into PEAR_Packager
  27994.         // so it'll be easy to implement "pear package --sign"
  27995.         if (sizeof($params) != 1) {
  27996.             return $this->raiseError("bad parameter(s), try \"help $command\"");
  27997.         }
  27998.         if (!file_exists($params[0])) {
  27999.             return $this->raiseError("file does not exist: $params[0]");
  28000.         }
  28001.         $obj = $this->getPackageFile($this->config, $this->_debug);
  28002.         $info = $obj->fromTgzFile($params[0], PEAR_VALIDATE_NORMAL);
  28003.         if (PEAR::isError($info)) {
  28004.             return $this->raiseError($info);
  28005.         }
  28006.         $tar = new Archive_Tar($params[0]);
  28007.         $tmpdir = System::mktemp('-d pearsign');
  28008.         if (!$tar->extractList('package2.xml package.xml package.sig', $tmpdir)) {
  28009.             return $this->raiseError("failed to extract tar file");
  28010.         }
  28011.         if (file_exists("$tmpdir/package.sig")) {
  28012.             return $this->raiseError("package already signed");
  28013.         }
  28014.         $packagexml = 'package.xml';
  28015.         if (file_exists("$tmpdir/package2.xml")) {
  28016.             $packagexml = 'package2.xml';
  28017.         }
  28018.         if (file_exists("$tmpdir/package.sig")) {
  28019.             unlink("$tmpdir/package.sig");
  28020.         }
  28021.         if (!file_exists("$tmpdir/$packagexml")) {
  28022.             return $this->raiseError("Extracted file $tmpdir/$packagexml not found.");
  28023.         }
  28024.         $input = $this->ui->userDialog($command,
  28025.                                        array('GnuPG Passphrase'),
  28026.                                        array('password'));
  28027.         if (!isset($input[0])) {
  28028.             //use empty passphrase
  28029.             $input[0] = '';
  28030.         }
  28031.  
  28032.         $devnull = (isset($options['verbose'])) ? '' : ' 2>/dev/null';
  28033.         $gpg = popen("gpg --batch --passphrase-fd 0 --armor --detach-sign --output $tmpdir/package.sig $tmpdir/$packagexml" . $devnull, "w");
  28034.         if (!$gpg) {
  28035.             return $this->raiseError("gpg command failed");
  28036.         }
  28037.         fwrite($gpg, "$input[0]\n");
  28038.         if (pclose($gpg) || !file_exists("$tmpdir/package.sig")) {
  28039.             return $this->raiseError("gpg sign failed");
  28040.         }
  28041.         if (!$tar->addModify("$tmpdir/package.sig", '', $tmpdir)) {
  28042.             return $this->raiseError('failed adding signature to file');
  28043.         }
  28044.  
  28045.         $this->ui->outputData("Package signed.", $command);
  28046.         return true;
  28047.     }
  28048.  
  28049.     // }}}
  28050.  
  28051.     /**
  28052.      * For unit testing purposes
  28053.      */
  28054.     function &getInstaller(&$ui)
  28055.     {
  28056.         if (!class_exists('PEAR_Installer')) {
  28057.             require_once 'PEAR/Installer.php';
  28058.         }
  28059.         $a = &new PEAR_Installer($ui);
  28060.         return $a;
  28061.     }
  28062.     
  28063.     /**
  28064.      * For unit testing purposes
  28065.      */
  28066.     function &getCommandPackaging(&$ui, &$config)
  28067.     {
  28068.         if (!class_exists('PEAR_Command_Packaging')) {
  28069.             if ($fp = @fopen('PEAR/Command/Packaging.php', 'r', true)) {
  28070.                 fclose($fp);
  28071.                 include_once 'PEAR/Command/Packaging.php';
  28072.             }
  28073.         }
  28074.         
  28075.         if (class_exists('PEAR_Command_Packaging')) {
  28076.             $a = &new PEAR_Command_Packaging($ui, $config);
  28077.         } else {
  28078.             $a = null;
  28079.         }
  28080.         return $a;
  28081.     }
  28082.  
  28083.     // {{{ doMakeRPM()
  28084.  
  28085.     function doMakeRPM($command, $options, $params)
  28086.     {
  28087.  
  28088.         // Check to see if PEAR_Command_Packaging is installed, and
  28089.         // transparently switch to use the "make-rpm-spec" command from it
  28090.         // instead, if it does. Otherwise, continue to use the old version
  28091.         // of "makerpm" supplied with this package (PEAR).
  28092.         $packaging_cmd = $this->getCommandPackaging($this->ui, $this->config);
  28093.         if ($packaging_cmd !== null) {
  28094.             $this->ui->outputData('PEAR_Command_Packaging is installed; using '.
  28095.                 'newer "make-rpm-spec" command instead');
  28096.             return $packaging_cmd->run('make-rpm-spec', $options, $params);
  28097.         } else {
  28098.             $this->ui->outputData('WARNING: "pear makerpm" is no longer available; an '.
  28099.               'improved version is available via "pear make-rpm-spec", which '.
  28100.               'is available by installing PEAR_Command_Packaging');
  28101.         }
  28102.         return true;
  28103.     }
  28104.  
  28105.     function doConvert($command, $options, $params)
  28106.     {
  28107.         $packagexml = isset($params[0]) ? $params[0] : 'package.xml';
  28108.         $newpackagexml = isset($params[1]) ? $params[1] : dirname($packagexml) .
  28109.             DIRECTORY_SEPARATOR . 'package2.xml';
  28110.         $pkg = &$this->getPackageFile($this->config, $this->_debug);
  28111.         PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  28112.         $pf = $pkg->fromPackageFile($packagexml, PEAR_VALIDATE_NORMAL);
  28113.         PEAR::staticPopErrorHandling();
  28114.         if (!PEAR::isError($pf)) {
  28115.             if (is_a($pf, 'PEAR_PackageFile_v2')) {
  28116.                 $this->ui->outputData($packagexml . ' is already a package.xml version 2.0');
  28117.                 return true;
  28118.             }
  28119.             $gen = &$pf->getDefaultGenerator();
  28120.             $newpf = &$gen->toV2();
  28121.             $newpf->setPackagefile($newpackagexml);
  28122.             $gen = &$newpf->getDefaultGenerator();
  28123.             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  28124.             $state = (isset($options['flat']) ? PEAR_VALIDATE_PACKAGING : PEAR_VALIDATE_NORMAL);
  28125.             $saved = $gen->toPackageFile(dirname($newpackagexml), $state,
  28126.                 basename($newpackagexml));
  28127.             PEAR::staticPopErrorHandling();
  28128.             if (PEAR::isError($saved)) {
  28129.                 if (is_array($saved->getUserInfo())) {
  28130.                     foreach ($saved->getUserInfo() as $warning) {
  28131.                         $this->ui->outputData($warning['message']);
  28132.                     }
  28133.                 }
  28134.                 $this->ui->outputData($saved->getMessage());
  28135.                 return true;
  28136.             }
  28137.             $this->ui->outputData('Wrote new version 2.0 package.xml to "' . $saved . '"');
  28138.             return true;
  28139.         } else {
  28140.             if (is_array($pf->getUserInfo())) {
  28141.                 foreach ($pf->getUserInfo() as $warning) {
  28142.                     $this->ui->outputData($warning['message']);
  28143.                 }
  28144.             }
  28145.             return $this->raiseError($pf);
  28146.         }
  28147.     }
  28148.  
  28149.     // }}}
  28150. }
  28151.  
  28152. ?>
  28153. PEAR-1.7.1/PEAR/Command/Pickle.xml100644   1750   1750        2761 10755221545  11543 <commands version="1.0">
  28154.  <pickle>
  28155.   <summary>Build PECL Package</summary>
  28156.   <function>doPackage</function>
  28157.   <shortcut>pi</shortcut>
  28158.   <options>
  28159.    <nocompress>
  28160.     <shortopt>Z</shortopt>
  28161.     <doc>Do not gzip the package file</doc>
  28162.    </nocompress>
  28163.    <showname>
  28164.     <shortopt>n</shortopt>
  28165.     <doc>Print the name of the packaged file.</doc>
  28166.    </showname>
  28167.   </options>
  28168.   <doc>[descfile] [descfile2]
  28169. Creates a PECL package from its description file (usually called
  28170. package.xml).  If a second packagefile is passed in, then
  28171. the packager will check to make sure that one is a package.xml
  28172. version 1.0, and the other is a package.xml version 2.0.  The
  28173. package.xml version 1.0 will be saved as "package.xml" in the archive,
  28174. and the other as "package2.xml" in the archive"
  28175.  
  28176. If no second file is passed in, and [descfile] is a package.xml 2.0,
  28177. an automatic conversion will be made to a package.xml 1.0.  Note that
  28178. only simple package.xml 2.0 will be converted.  package.xml 2.0 with:
  28179.  
  28180.  - dependency types other than required/optional PECL package/ext/php/pearinstaller
  28181.  - more than one extsrcrelease/zendextsrcrelease
  28182.  - zendextbinrelease, extbinrelease, phprelease, or bundle release type
  28183.  - dependency groups
  28184.  - ignore tags in release filelist
  28185.  - tasks other than replace
  28186.  - custom roles
  28187.  
  28188. will cause pickle to fail, and output an error message.  If your package2.xml
  28189. uses any of these features, you are best off using PEAR_PackageFileManager to
  28190. generate both package.xml.</doc>
  28191.  </pickle>
  28192. </commands>PEAR-1.7.1/PEAR/Command/Pickle.php100644   1750   1750       37420 10755221545  11552 <?php
  28193. /**
  28194.  * PEAR_Command_Pickle (pickle command)
  28195.  *
  28196.  * PHP versions 4 and 5
  28197.  *
  28198.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  28199.  * that is available through the world-wide-web at the following URI:
  28200.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  28201.  * the PHP License and are unable to obtain it through the web, please
  28202.  * send a note to license@php.net so we can mail you a copy immediately.
  28203.  *
  28204.  * @category   pear
  28205.  * @package    PEAR
  28206.  * @author     Greg Beaver <cellog@php.net>
  28207.  * @copyright  2005-2008 The PHP Group
  28208.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  28209.  * @version    CVS: $Id: Pickle.php,v 1.8 2008/01/29 03:21:01 cellog Exp $
  28210.  * @link       http://pear.php.net/package/PEAR
  28211.  * @since      File available since Release 1.4.1
  28212.  */
  28213.  
  28214. /**
  28215.  * base class
  28216.  */
  28217. require_once 'PEAR/Command/Common.php';
  28218.  
  28219. /**
  28220.  * PEAR commands for login/logout
  28221.  *
  28222.  * @category   pear
  28223.  * @package    PEAR
  28224.  * @author     Greg Beaver <cellog@php.net>
  28225.  * @copyright  2005-2008 The PHP Group
  28226.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  28227.  * @version    Release: 1.7.1
  28228.  * @link       http://pear.php.net/package/PEAR
  28229.  * @since      Class available since Release 1.4.1
  28230.  */
  28231.  
  28232. class PEAR_Command_Pickle extends PEAR_Command_Common
  28233. {
  28234.     var $commands = array(
  28235.         'pickle' => array(
  28236.             'summary' => 'Build PECL Package',
  28237.             'function' => 'doPackage',
  28238.             'shortcut' => 'pi',
  28239.             'options' => array(
  28240.                 'nocompress' => array(
  28241.                     'shortopt' => 'Z',
  28242.                     'doc' => 'Do not gzip the package file'
  28243.                     ),
  28244.                 'showname' => array(
  28245.                     'shortopt' => 'n',
  28246.                     'doc' => 'Print the name of the packaged file.',
  28247.                     ),
  28248.                 ),
  28249.             'doc' => '[descfile]
  28250. Creates a PECL package from its package2.xml file.
  28251.  
  28252. An automatic conversion will be made to a package.xml 1.0 and written out to
  28253. disk in the current directory