"Fossies" - the Fresh Open Source Software Archive

Member "canopy-3.0.7/lib/pear/PEAR/REST/10.php" (1 Nov 2019, 32644 Bytes) of package /linux/www/canopy-3.0.7.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) PHP source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "10.php" see the Fossies "Dox" file reference documentation.

    1 <?php
    2 /**
    3  * PEAR_REST_10
    4  *
    5  * PHP versions 4 and 5
    6  *
    7  * @category   pear
    8  * @package    PEAR
    9  * @author     Greg Beaver <cellog@php.net>
   10  * @copyright  1997-2009 The Authors
   11  * @license    http://opensource.org/licenses/bsd-license.php New BSD License
   12  * @version    CVS: $Id: 10.php 287558 2009-08-21 22:21:28Z dufuz $
   13  * @link       http://pear.php.net/package/PEAR
   14  * @since      File available since Release 1.4.0a12
   15  */
   16 
   17 /**
   18  * For downloading REST xml/txt files
   19  */
   20 require_once 'PEAR/REST.php';
   21 
   22 /**
   23  * Implement REST 1.0
   24  *
   25  * @category   pear
   26  * @package    PEAR
   27  * @author     Greg Beaver <cellog@php.net>
   28  * @copyright  1997-2009 The Authors
   29  * @license    http://opensource.org/licenses/bsd-license.php New BSD License
   30  * @version    Release: 1.9.0
   31  * @link       http://pear.php.net/package/PEAR
   32  * @since      Class available since Release 1.4.0a12
   33  */
   34 class PEAR_REST_10
   35 {
   36     /**
   37      * @var PEAR_REST
   38      */
   39     var $_rest;
   40     function PEAR_REST_10($config, $options = array())
   41     {
   42         $this->_rest = new PEAR_REST($config, $options);
   43     }
   44 
   45     /**
   46      * Retrieve information about a remote package to be downloaded from a REST server
   47      *
   48      * @param string $base The uri to prepend to all REST calls
   49      * @param array $packageinfo an array of format:
   50      * <pre>
   51      *  array(
   52      *   'package' => 'packagename',
   53      *   'channel' => 'channelname',
   54      *  ['state' => 'alpha' (or valid state),]
   55      *  -or-
   56      *  ['version' => '1.whatever']
   57      * </pre>
   58      * @param string $prefstate Current preferred_state config variable value
   59      * @param bool $installed the installed version of this package to compare against
   60      * @return array|false|PEAR_Error see {@link _returnDownloadURL()}
   61      */
   62     function getDownloadURL($base, $packageinfo, $prefstate, $installed, $channel = false)
   63     {
   64         $states = $this->betterStates($prefstate, true);
   65         if (!$states) {
   66             return PEAR::raiseError('"' . $prefstate . '" is not a valid state');
   67         }
   68 
   69         $channel  = $packageinfo['channel'];
   70         $package  = $packageinfo['package'];
   71         $state    = isset($packageinfo['state'])   ? $packageinfo['state']   : null;
   72         $version  = isset($packageinfo['version']) ? $packageinfo['version'] : null;
   73         $restFile = $base . 'r/' . strtolower($package) . '/allreleases.xml';
   74 
   75         $info = $this->_rest->retrieveData($restFile, false, false, $channel);
   76         if (PEAR::isError($info)) {
   77             return PEAR::raiseError('No releases available for package "' .
   78                 $channel . '/' . $package . '"');
   79         }
   80 
   81         if (!isset($info['r'])) {
   82             return false;
   83         }
   84 
   85         $release = $found = false;
   86         if (!is_array($info['r']) || !isset($info['r'][0])) {
   87             $info['r'] = array($info['r']);
   88         }
   89 
   90         foreach ($info['r'] as $release) {
   91             if (!isset($this->_rest->_options['force']) && ($installed &&
   92                   version_compare($release['v'], $installed, '<'))) {
   93                 continue;
   94             }
   95 
   96             if (isset($state)) {
   97                 // try our preferred state first
   98                 if ($release['s'] == $state) {
   99                     $found = true;
  100                     break;
  101                 }
  102                 // see if there is something newer and more stable
  103                 // bug #7221
  104                 if (in_array($release['s'], $this->betterStates($state), true)) {
  105                     $found = true;
  106                     break;
  107                 }
  108             } elseif (isset($version)) {
  109                 if ($release['v'] == $version) {
  110                     $found = true;
  111                     break;
  112                 }
  113             } else {
  114                 if (in_array($release['s'], $states)) {
  115                     $found = true;
  116                     break;
  117                 }
  118             }
  119         }
  120 
  121         return $this->_returnDownloadURL($base, $package, $release, $info, $found, false, $channel);
  122     }
  123 
  124     function getDepDownloadURL($base, $xsdversion, $dependency, $deppackage,
  125                                $prefstate = 'stable', $installed = false, $channel = false)
  126     {
  127         $states = $this->betterStates($prefstate, true);
  128         if (!$states) {
  129             return PEAR::raiseError('"' . $prefstate . '" is not a valid state');
  130         }
  131 
  132         $channel  = $dependency['channel'];
  133         $package  = $dependency['name'];
  134         $state    = isset($dependency['state'])   ? $dependency['state']   : null;
  135         $version  = isset($dependency['version']) ? $dependency['version'] : null;
  136         $restFile = $base . 'r/' . strtolower($package) . '/allreleases.xml';
  137 
  138         $info = $this->_rest->retrieveData($restFile, false, false, $channel);
  139         if (PEAR::isError($info)) {
  140             return PEAR::raiseError('Package "' . $deppackage['channel'] . '/' . $deppackage['package']
  141                 . '" dependency "' . $channel . '/' . $package . '" has no releases');
  142         }
  143 
  144         if (!is_array($info) || !isset($info['r'])) {
  145             return false;
  146         }
  147 
  148         $exclude = array();
  149         $min = $max = $recommended = false;
  150         if ($xsdversion == '1.0') {
  151             switch ($dependency['rel']) {
  152                 case 'ge' :
  153                     $min = $dependency['version'];
  154                 break;
  155                 case 'gt' :
  156                     $min = $dependency['version'];
  157                     $exclude = array($dependency['version']);
  158                 break;
  159                 case 'eq' :
  160                     $recommended = $dependency['version'];
  161                 break;
  162                 case 'lt' :
  163                     $max = $dependency['version'];
  164                     $exclude = array($dependency['version']);
  165                 break;
  166                 case 'le' :
  167                     $max = $dependency['version'];
  168                 break;
  169                 case 'ne' :
  170                     $exclude = array($dependency['version']);
  171                 break;
  172             }
  173         } else {
  174             $min = isset($dependency['min']) ? $dependency['min'] : false;
  175             $max = isset($dependency['max']) ? $dependency['max'] : false;
  176             $recommended = isset($dependency['recommended']) ?
  177                 $dependency['recommended'] : false;
  178             if (isset($dependency['exclude'])) {
  179                 if (!isset($dependency['exclude'][0])) {
  180                     $exclude = array($dependency['exclude']);
  181                 }
  182             }
  183         }
  184         $release = $found = false;
  185         if (!is_array($info['r']) || !isset($info['r'][0])) {
  186             $info['r'] = array($info['r']);
  187         }
  188         foreach ($info['r'] as $release) {
  189             if (!isset($this->_rest->_options['force']) && ($installed &&
  190                   version_compare($release['v'], $installed, '<'))) {
  191                 continue;
  192             }
  193             if (in_array($release['v'], $exclude)) { // skip excluded versions
  194                 continue;
  195             }
  196             // allow newer releases to say "I'm OK with the dependent package"
  197             if ($xsdversion == '2.0' && isset($release['co'])) {
  198                 if (!is_array($release['co']) || !isset($release['co'][0])) {
  199                     $release['co'] = array($release['co']);
  200                 }
  201                 foreach ($release['co'] as $entry) {
  202                     if (isset($entry['x']) && !is_array($entry['x'])) {
  203                         $entry['x'] = array($entry['x']);
  204                     } elseif (!isset($entry['x'])) {
  205                         $entry['x'] = array();
  206                     }
  207                     if ($entry['c'] == $deppackage['channel'] &&
  208                           strtolower($entry['p']) == strtolower($deppackage['package']) &&
  209                           version_compare($deppackage['version'], $entry['min'], '>=') &&
  210                           version_compare($deppackage['version'], $entry['max'], '<=') &&
  211                           !in_array($release['v'], $entry['x'])) {
  212                         $recommended = $release['v'];
  213                         break;
  214                     }
  215                 }
  216             }
  217             if ($recommended) {
  218                 if ($release['v'] != $recommended) { // if we want a specific
  219                     // version, then skip all others
  220                     continue;
  221                 } else {
  222                     if (!in_array($release['s'], $states)) {
  223                         // the stability is too low, but we must return the
  224                         // recommended version if possible
  225                         return $this->_returnDownloadURL($base, $package, $release, $info, true, false, $channel);
  226                     }
  227                 }
  228             }
  229             if ($min && version_compare($release['v'], $min, 'lt')) { // skip too old versions
  230                 continue;
  231             }
  232             if ($max && version_compare($release['v'], $max, 'gt')) { // skip too new versions
  233                 continue;
  234             }
  235             if ($installed && version_compare($release['v'], $installed, '<')) {
  236                 continue;
  237             }
  238             if (in_array($release['s'], $states)) { // if in the preferred state...
  239                 $found = true; // ... then use it
  240                 break;
  241             }
  242         }
  243         return $this->_returnDownloadURL($base, $package, $release, $info, $found, false, $channel);
  244     }
  245 
  246     /**
  247      * Take raw data and return the array needed for processing a download URL
  248      *
  249      * @param string $base REST base uri
  250      * @param string $package Package name
  251      * @param array $release an array of format array('v' => version, 's' => state)
  252      *                       describing the release to download
  253      * @param array $info list of all releases as defined by allreleases.xml
  254      * @param bool|null $found determines whether the release was found or this is the next
  255      *                    best alternative.  If null, then versions were skipped because
  256      *                    of PHP dependency
  257      * @return array|PEAR_Error
  258      * @access private
  259      */
  260     function _returnDownloadURL($base, $package, $release, $info, $found, $phpversion = false, $channel = false)
  261     {
  262         if (!$found) {
  263             $release = $info['r'][0];
  264         }
  265 
  266         $packageLower = strtolower($package);
  267         $pinfo = $this->_rest->retrieveCacheFirst($base . 'p/' . $packageLower . '/' .
  268             'info.xml', false, false, $channel);
  269         if (PEAR::isError($pinfo)) {
  270             return PEAR::raiseError('Package "' . $package .
  271                 '" does not have REST info xml available');
  272         }
  273 
  274         $releaseinfo = $this->_rest->retrieveCacheFirst($base . 'r/' . $packageLower . '/' .
  275             $release['v'] . '.xml', false, false, $channel);
  276         if (PEAR::isError($releaseinfo)) {
  277             return PEAR::raiseError('Package "' . $package . '" Version "' . $release['v'] .
  278                 '" does not have REST xml available');
  279         }
  280 
  281         $packagexml = $this->_rest->retrieveCacheFirst($base . 'r/' . $packageLower . '/' .
  282             'deps.' . $release['v'] . '.txt', false, true, $channel);
  283         if (PEAR::isError($packagexml)) {
  284             return PEAR::raiseError('Package "' . $package . '" Version "' . $release['v'] .
  285                 '" does not have REST dependency information available');
  286         }
  287 
  288         $packagexml = unserialize($packagexml);
  289         if (!$packagexml) {
  290             $packagexml = array();
  291         }
  292 
  293         $allinfo = $this->_rest->retrieveData($base . 'r/' . $packageLower .
  294             '/allreleases.xml', false, false, $channel);
  295         if (!is_array($allinfo['r']) || !isset($allinfo['r'][0])) {
  296             $allinfo['r'] = array($allinfo['r']);
  297         }
  298 
  299         $compatible = false;
  300         foreach ($allinfo['r'] as $release) {
  301             if ($release['v'] != $releaseinfo['v']) {
  302                 continue;
  303             }
  304 
  305             if (!isset($release['co'])) {
  306                 break;
  307             }
  308 
  309             $compatible = array();
  310             if (!is_array($release['co']) || !isset($release['co'][0])) {
  311                 $release['co'] = array($release['co']);
  312             }
  313 
  314             foreach ($release['co'] as $entry) {
  315                 $comp = array();
  316                 $comp['name']    = $entry['p'];
  317                 $comp['channel'] = $entry['c'];
  318                 $comp['min']     = $entry['min'];
  319                 $comp['max']     = $entry['max'];
  320                 if (isset($entry['x']) && !is_array($entry['x'])) {
  321                     $comp['exclude'] = $entry['x'];
  322                 }
  323 
  324                 $compatible[] = $comp;
  325             }
  326 
  327             if (count($compatible) == 1) {
  328                 $compatible = $compatible[0];
  329             }
  330 
  331             break;
  332         }
  333 
  334         $deprecated = false;
  335         if (isset($pinfo['dc']) && isset($pinfo['dp'])) {
  336             if (is_array($pinfo['dp'])) {
  337                 $deprecated = array('channel' => (string) $pinfo['dc'],
  338                                     'package' => trim($pinfo['dp']['_content']));
  339             } else {
  340                 $deprecated = array('channel' => (string) $pinfo['dc'],
  341                                     'package' => trim($pinfo['dp']));
  342             }
  343         }
  344 
  345         $return = array(
  346             'version'    => $releaseinfo['v'],
  347             'info'       => $packagexml,
  348             'package'    => $releaseinfo['p']['_content'],
  349             'stability'  => $releaseinfo['st'],
  350             'compatible' => $compatible,
  351             'deprecated' => $deprecated,
  352         );
  353 
  354         if ($found) {
  355             $return['url'] = $releaseinfo['g'];
  356             return $return;
  357         }
  358 
  359         $return['php'] = $phpversion;
  360         return $return;
  361     }
  362 
  363     function listPackages($base, $channel = false)
  364     {
  365         $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel);
  366         if (PEAR::isError($packagelist)) {
  367             return $packagelist;
  368         }
  369 
  370         if (!is_array($packagelist) || !isset($packagelist['p'])) {
  371             return array();
  372         }
  373 
  374         if (!is_array($packagelist['p'])) {
  375             $packagelist['p'] = array($packagelist['p']);
  376         }
  377 
  378         return $packagelist['p'];
  379     }
  380 
  381     /**
  382      * List all categories of a REST server
  383      *
  384      * @param string $base base URL of the server
  385      * @return array of categorynames
  386      */
  387     function listCategories($base, $channel = false)
  388     {
  389         $categories = array();
  390 
  391         // c/categories.xml does not exist;
  392         // check for every package its category manually
  393         // This is SLOOOWWWW : ///
  394         $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel);
  395         if (PEAR::isError($packagelist)) {
  396             return $packagelist;
  397         }
  398 
  399         if (!is_array($packagelist) || !isset($packagelist['p'])) {
  400             $ret = array();
  401             return $ret;
  402         }
  403 
  404         if (!is_array($packagelist['p'])) {
  405             $packagelist['p'] = array($packagelist['p']);
  406         }
  407 
  408         PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  409         foreach ($packagelist['p'] as $package) {
  410                 $inf = $this->_rest->retrieveData($base . 'p/' . strtolower($package) . '/info.xml', false, false, $channel);
  411                 if (PEAR::isError($inf)) {
  412                     PEAR::popErrorHandling();
  413                     return $inf;
  414                 }
  415                 $cat = $inf['ca']['_content'];
  416                 if (!isset($categories[$cat])) {
  417                     $categories[$cat] = $inf['ca'];
  418                 }
  419         }
  420 
  421         return array_values($categories);
  422     }
  423 
  424     /**
  425      * List a category of a REST server
  426      *
  427      * @param string $base base URL of the server
  428      * @param string $category name of the category
  429      * @param boolean $info also download full package info
  430      * @return array of packagenames
  431      */
  432     function listCategory($base, $category, $info = false, $channel = false)
  433     {
  434         // gives '404 Not Found' error when category doesn't exist
  435         $packagelist = $this->_rest->retrieveData($base.'c/'.urlencode($category).'/packages.xml', false, false, $channel);
  436         if (PEAR::isError($packagelist)) {
  437             return $packagelist;
  438         }
  439 
  440         if (!is_array($packagelist) || !isset($packagelist['p'])) {
  441             return array();
  442         }
  443 
  444         if (!is_array($packagelist['p']) ||
  445             !isset($packagelist['p'][0])) { // only 1 pkg
  446             $packagelist = array($packagelist['p']);
  447         } else {
  448             $packagelist = $packagelist['p'];
  449         }
  450 
  451         if ($info == true) {
  452             // get individual package info
  453             PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  454             foreach ($packagelist as $i => $packageitem) {
  455                 $url = sprintf('%s'.'r/%s/latest.txt',
  456                         $base,
  457                         strtolower($packageitem['_content']));
  458                 $version = $this->_rest->retrieveData($url, false, false, $channel);
  459                 if (PEAR::isError($version)) {
  460                     break; // skipit
  461                 }
  462                 $url = sprintf('%s'.'r/%s/%s.xml',
  463                         $base,
  464                         strtolower($packageitem['_content']),
  465                         $version);
  466                 $info = $this->_rest->retrieveData($url, false, false, $channel);
  467                 if (PEAR::isError($info)) {
  468                     break; // skipit
  469                 }
  470                 $packagelist[$i]['info'] = $info;
  471             }
  472             PEAR::popErrorHandling();
  473         }
  474 
  475         return $packagelist;
  476     }
  477 
  478 
  479     function listAll($base, $dostable, $basic = true, $searchpackage = false, $searchsummary = false, $channel = false)
  480     {
  481         $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel);
  482         if (PEAR::isError($packagelist)) {
  483             return $packagelist;
  484         }
  485         if ($this->_rest->config->get('verbose') > 0) {
  486             $ui = &PEAR_Frontend::singleton();
  487             $ui->log('Retrieving data...0%', true);
  488         }
  489         $ret = array();
  490         if (!is_array($packagelist) || !isset($packagelist['p'])) {
  491             return $ret;
  492         }
  493         if (!is_array($packagelist['p'])) {
  494             $packagelist['p'] = array($packagelist['p']);
  495         }
  496 
  497         // only search-packagename = quicksearch !
  498         if ($searchpackage && (!$searchsummary || empty($searchpackage))) {
  499             $newpackagelist = array();
  500             foreach ($packagelist['p'] as $package) {
  501                 if (!empty($searchpackage) && stristr($package, $searchpackage) !== false) {
  502                     $newpackagelist[] = $package;
  503                 }
  504             }
  505             $packagelist['p'] = $newpackagelist;
  506         }
  507         PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  508         $next = .1;
  509         foreach ($packagelist['p'] as $progress => $package) {
  510             if ($this->_rest->config->get('verbose') > 0) {
  511                 if ($progress / count($packagelist['p']) >= $next) {
  512                     if ($next == .5) {
  513                         $ui->log('50%', false);
  514                     } else {
  515                         $ui->log('.', false);
  516                     }
  517                     $next += .1;
  518                 }
  519             }
  520 
  521             if ($basic) { // remote-list command
  522                 if ($dostable) {
  523                     $latest = $this->_rest->retrieveData($base . 'r/' . strtolower($package) .
  524                         '/stable.txt', false, false, $channel);
  525                 } else {
  526                     $latest = $this->_rest->retrieveData($base . 'r/' . strtolower($package) .
  527                         '/latest.txt', false, false, $channel);
  528                 }
  529                 if (PEAR::isError($latest)) {
  530                     $latest = false;
  531                 }
  532                 $info = array('stable' => $latest);
  533             } else { // list-all command
  534                 $inf = $this->_rest->retrieveData($base . 'p/' . strtolower($package) . '/info.xml', false, false, $channel);
  535                 if (PEAR::isError($inf)) {
  536                     PEAR::popErrorHandling();
  537                     return $inf;
  538                 }
  539                 if ($searchpackage) {
  540                     $found = (!empty($searchpackage) && stristr($package, $searchpackage) !== false);
  541                     if (!$found && !(isset($searchsummary) && !empty($searchsummary)
  542                         && (stristr($inf['s'], $searchsummary) !== false
  543                             || stristr($inf['d'], $searchsummary) !== false)))
  544                     {
  545                         continue;
  546                     };
  547                 }
  548                 $releases = $this->_rest->retrieveData($base . 'r/' . strtolower($package) .
  549                     '/allreleases.xml', false, false, $channel);
  550                 if (PEAR::isError($releases)) {
  551                     continue;
  552                 }
  553                 if (!isset($releases['r'][0])) {
  554                     $releases['r'] = array($releases['r']);
  555                 }
  556                 unset($latest);
  557                 unset($unstable);
  558                 unset($stable);
  559                 unset($state);
  560                 foreach ($releases['r'] as $release) {
  561                     if (!isset($latest)) {
  562                         if ($dostable && $release['s'] == 'stable') {
  563                             $latest = $release['v'];
  564                             $state = 'stable';
  565                         }
  566                         if (!$dostable) {
  567                             $latest = $release['v'];
  568                             $state = $release['s'];
  569                         }
  570                     }
  571                     if (!isset($stable) && $release['s'] == 'stable') {
  572                         $stable = $release['v'];
  573                         if (!isset($unstable)) {
  574                             $unstable = $stable;
  575                         }
  576                     }
  577                     if (!isset($unstable) && $release['s'] != 'stable') {
  578                         $latest = $unstable = $release['v'];
  579                         $state = $release['s'];
  580                     }
  581                     if (isset($latest) && !isset($state)) {
  582                         $state = $release['s'];
  583                     }
  584                     if (isset($latest) && isset($stable) && isset($unstable)) {
  585                         break;
  586                     }
  587                 }
  588                 $deps = array();
  589                 if (!isset($unstable)) {
  590                     $unstable = false;
  591                     $state = 'stable';
  592                     if (isset($stable)) {
  593                         $latest = $unstable = $stable;
  594                     }
  595                 } else {
  596                     $latest = $unstable;
  597                 }
  598                 if (!isset($latest)) {
  599                     $latest = false;
  600                 }
  601                 if ($latest) {
  602                     $d = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/deps.' .
  603                         $latest . '.txt', false, false, $channel);
  604                     if (!PEAR::isError($d)) {
  605                         $d = unserialize($d);
  606                         if ($d) {
  607                             if (isset($d['required'])) {
  608                                 if (!class_exists('PEAR_PackageFile_v2')) {
  609                                     require_once 'PEAR/PackageFile/v2.php';
  610                                 }
  611                                 if (!isset($pf)) {
  612                                     $pf = new PEAR_PackageFile_v2;
  613                                 }
  614                                 $pf->setDeps($d);
  615                                 $tdeps = $pf->getDeps();
  616                             } else {
  617                                 $tdeps = $d;
  618                             }
  619                             foreach ($tdeps as $dep) {
  620                                 if ($dep['type'] !== 'pkg') {
  621                                     continue;
  622                                 }
  623                                 $deps[] = $dep;
  624                             }
  625                         }
  626                     }
  627                 }
  628                 if (!isset($stable)) {
  629                     $stable = '-n/a-';
  630                 }
  631                 if (!$searchpackage) {
  632                     $info = array('stable' => $latest, 'summary' => $inf['s'], 'description' =>
  633                         $inf['d'], 'deps' => $deps, 'category' => $inf['ca']['_content'],
  634                         'unstable' => $unstable, 'state' => $state);
  635                 } else {
  636                     $info = array('stable' => $stable, 'summary' => $inf['s'], 'description' =>
  637                         $inf['d'], 'deps' => $deps, 'category' => $inf['ca']['_content'],
  638                         'unstable' => $unstable, 'state' => $state);
  639                 }
  640             }
  641             $ret[$package] = $info;
  642         }
  643         PEAR::popErrorHandling();
  644         return $ret;
  645     }
  646 
  647     function listLatestUpgrades($base, $pref_state, $installed, $channel, &$reg)
  648     {
  649         $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel);
  650         if (PEAR::isError($packagelist)) {
  651             return $packagelist;
  652         }
  653 
  654         $ret = array();
  655         if (!is_array($packagelist) || !isset($packagelist['p'])) {
  656             return $ret;
  657         }
  658 
  659         if (!is_array($packagelist['p'])) {
  660             $packagelist['p'] = array($packagelist['p']);
  661         }
  662 
  663         foreach ($packagelist['p'] as $package) {
  664             if (!isset($installed[strtolower($package)])) {
  665                 continue;
  666             }
  667 
  668             $inst_version = $reg->packageInfo($package, 'version', $channel);
  669             $inst_state   = $reg->packageInfo($package, 'release_state', $channel);
  670             PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  671             $info = $this->_rest->retrieveData($base . 'r/' . strtolower($package) .
  672                 '/allreleases.xml', false, false, $channel);
  673             PEAR::popErrorHandling();
  674             if (PEAR::isError($info)) {
  675                 continue; // no remote releases
  676             }
  677 
  678             if (!isset($info['r'])) {
  679                 continue;
  680             }
  681 
  682             $release = $found = false;
  683             if (!is_array($info['r']) || !isset($info['r'][0])) {
  684                 $info['r'] = array($info['r']);
  685             }
  686 
  687             // $info['r'] is sorted by version number
  688             usort($info['r'], array($this, '_sortReleasesByVersionNumber'));
  689             foreach ($info['r'] as $release) {
  690                 if ($inst_version && version_compare($release['v'], $inst_version, '<=')) {
  691                     // not newer than the one installed
  692                     break;
  693                 }
  694 
  695                 // new version > installed version
  696                 if (!$pref_state) {
  697                     // every state is a good state
  698                     $found = true;
  699                     break;
  700                 } else {
  701                     $new_state = $release['s'];
  702                     // if new state >= installed state: go
  703                     if (in_array($new_state, $this->betterStates($inst_state, true))) {
  704                         $found = true;
  705                         break;
  706                     } else {
  707                         // only allow to lower the state of package,
  708                         // if new state >= preferred state: go
  709                         if (in_array($new_state, $this->betterStates($pref_state, true))) {
  710                             $found = true;
  711                             break;
  712                         }
  713                     }
  714                 }
  715             }
  716 
  717             if (!$found) {
  718                 continue;
  719             }
  720 
  721             $relinfo = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/' .
  722                 $release['v'] . '.xml', false, false, $channel);
  723             if (PEAR::isError($relinfo)) {
  724                 return $relinfo;
  725             }
  726 
  727             $ret[$package] = array(
  728                 'version'  => $release['v'],
  729                 'state'    => $release['s'],
  730                 'filesize' => $relinfo['f'],
  731             );
  732         }
  733 
  734         return $ret;
  735     }
  736 
  737     function packageInfo($base, $package, $channel = false)
  738     {
  739         PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  740         $pinfo = $this->_rest->retrieveData($base . 'p/' . strtolower($package) . '/info.xml', false, false, $channel);
  741         if (PEAR::isError($pinfo)) {
  742             PEAR::popErrorHandling();
  743             return PEAR::raiseError('Unknown package: "' . $package . '" in channel "' . $channel . '"' . "\n". 'Debug: ' .
  744                 $pinfo->getMessage());
  745         }
  746 
  747         $releases = array();
  748         $allreleases = $this->_rest->retrieveData($base . 'r/' . strtolower($package) .
  749             '/allreleases.xml', false, false, $channel);
  750         if (!PEAR::isError($allreleases)) {
  751             if (!class_exists('PEAR_PackageFile_v2')) {
  752                 require_once 'PEAR/PackageFile/v2.php';
  753             }
  754 
  755             if (!is_array($allreleases['r']) || !isset($allreleases['r'][0])) {
  756                 $allreleases['r'] = array($allreleases['r']);
  757             }
  758 
  759             $pf = new PEAR_PackageFile_v2;
  760             foreach ($allreleases['r'] as $release) {
  761                 $ds = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/deps.' .
  762                     $release['v'] . '.txt', false, false, $channel);
  763                 if (PEAR::isError($ds)) {
  764                     continue;
  765                 }
  766 
  767                 if (!isset($latest)) {
  768                     $latest = $release['v'];
  769                 }
  770 
  771                 $pf->setDeps(unserialize($ds));
  772                 $ds = $pf->getDeps();
  773                 $info = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package)
  774                     . '/' . $release['v'] . '.xml', false, false, $channel);
  775 
  776                 if (PEAR::isError($info)) {
  777                     continue;
  778                 }
  779 
  780                 $releases[$release['v']] = array(
  781                     'doneby' => $info['m'],
  782                     'license' => $info['l'],
  783                     'summary' => $info['s'],
  784                     'description' => $info['d'],
  785                     'releasedate' => $info['da'],
  786                     'releasenotes' => $info['n'],
  787                     'state' => $release['s'],
  788                     'deps' => $ds ? $ds : array(),
  789                 );
  790             }
  791         } else {
  792             $latest = '';
  793         }
  794 
  795         PEAR::popErrorHandling();
  796         if (isset($pinfo['dc']) && isset($pinfo['dp'])) {
  797             if (is_array($pinfo['dp'])) {
  798                 $deprecated = array('channel' => (string) $pinfo['dc'],
  799                                     'package' => trim($pinfo['dp']['_content']));
  800             } else {
  801                 $deprecated = array('channel' => (string) $pinfo['dc'],
  802                                     'package' => trim($pinfo['dp']));
  803             }
  804         } else {
  805             $deprecated = false;
  806         }
  807 
  808         if (!isset($latest)) {
  809             $latest = '';
  810         }
  811 
  812         return array(
  813             'name' => $pinfo['n'],
  814             'channel' => $pinfo['c'],
  815             'category' => $pinfo['ca']['_content'],
  816             'stable' => $latest,
  817             'license' => $pinfo['l'],
  818             'summary' => $pinfo['s'],
  819             'description' => $pinfo['d'],
  820             'releases' => $releases,
  821             'deprecated' => $deprecated,
  822             );
  823     }
  824 
  825     /**
  826      * Return an array containing all of the states that are more stable than
  827      * or equal to the passed in state
  828      *
  829      * @param string Release state
  830      * @param boolean Determines whether to include $state in the list
  831      * @return false|array False if $state is not a valid release state
  832      */
  833     function betterStates($state, $include = false)
  834     {
  835         static $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable');
  836         $i = array_search($state, $states);
  837         if ($i === false) {
  838             return false;
  839         }
  840 
  841         if ($include) {
  842             $i--;
  843         }
  844 
  845         return array_slice($states, $i + 1);
  846     }
  847 
  848     /**
  849      * Sort releases by version number
  850      *
  851      * @access private
  852      */
  853     function _sortReleasesByVersionNumber($a, $b)
  854     {
  855         if (version_compare($a['v'], $b['v'], '=')) {
  856             return 0;
  857         }
  858 
  859         if (version_compare($a['v'], $b['v'], '>')) {
  860             return -1;
  861         }
  862 
  863         if (version_compare($a['v'], $b['v'], '<')) {
  864             return 1;
  865         }
  866     }
  867 }