PageRenderTime 87ms CodeModel.GetById 21ms app.highlight 55ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/php/PEAR/Downloader/Package.php

https://bitbucket.org/adarshj/convenient_website
PHP | 1988 lines | 1509 code | 230 blank | 249 comment | 393 complexity | 2a4bfddd597fcb1d63b2a06ea4544b91 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1<?php
   2/**
   3 * PEAR_Downloader_Package
   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: Package.php 313023 2011-07-06 19:17:11Z dufuz $
  13 * @link       http://pear.php.net/package/PEAR
  14 * @since      File available since Release 1.4.0a1
  15 */
  16
  17/**
  18 * Error code when parameter initialization fails because no releases
  19 * exist within preferred_state, but releases do exist
  20 */
  21define('PEAR_DOWNLOADER_PACKAGE_STATE', -1003);
  22/**
  23 * Error code when parameter initialization fails because no releases
  24 * exist that will work with the existing PHP version
  25 */
  26define('PEAR_DOWNLOADER_PACKAGE_PHPVERSION', -1004);
  27
  28/**
  29 * Coordinates download parameters and manages their dependencies
  30 * prior to downloading them.
  31 *
  32 * Input can come from three sources:
  33 *
  34 * - local files (archives or package.xml)
  35 * - remote files (downloadable urls)
  36 * - abstract package names
  37 *
  38 * The first two elements are handled cleanly by PEAR_PackageFile, but the third requires
  39 * accessing pearweb's xml-rpc interface to determine necessary dependencies, and the
  40 * format returned of dependencies is slightly different from that used in package.xml.
  41 *
  42 * This class hides the differences between these elements, and makes automatic
  43 * dependency resolution a piece of cake.  It also manages conflicts when
  44 * two classes depend on incompatible dependencies, or differing versions of the same
  45 * package dependency.  In addition, download will not be attempted if the php version is
  46 * not supported, PEAR installer version is not supported, or non-PECL extensions are not
  47 * installed.
  48 * @category   pear
  49 * @package    PEAR
  50 * @author     Greg Beaver <cellog@php.net>
  51 * @copyright  1997-2009 The Authors
  52 * @license    http://opensource.org/licenses/bsd-license.php New BSD License
  53 * @version    Release: 1.9.4
  54 * @link       http://pear.php.net/package/PEAR
  55 * @since      Class available since Release 1.4.0a1
  56 */
  57class PEAR_Downloader_Package
  58{
  59    /**
  60     * @var PEAR_Downloader
  61     */
  62    var $_downloader;
  63    /**
  64     * @var PEAR_Config
  65     */
  66    var $_config;
  67    /**
  68     * @var PEAR_Registry
  69     */
  70    var $_registry;
  71    /**
  72     * Used to implement packagingroot properly
  73     * @var PEAR_Registry
  74     */
  75    var $_installRegistry;
  76    /**
  77     * @var PEAR_PackageFile_v1|PEAR_PackageFile|v2
  78     */
  79    var $_packagefile;
  80    /**
  81     * @var array
  82     */
  83    var $_parsedname;
  84    /**
  85     * @var array
  86     */
  87    var $_downloadURL;
  88    /**
  89     * @var array
  90     */
  91    var $_downloadDeps = array();
  92    /**
  93     * @var boolean
  94     */
  95    var $_valid = false;
  96    /**
  97     * @var boolean
  98     */
  99    var $_analyzed = false;
 100    /**
 101     * if this or a parent package was invoked with Package-state, this is set to the
 102     * state variable.
 103     *
 104     * This allows temporary reassignment of preferred_state for a parent package and all of
 105     * its dependencies.
 106     * @var string|false
 107     */
 108    var $_explicitState = false;
 109    /**
 110     * If this package is invoked with Package#group, this variable will be true
 111     */
 112    var $_explicitGroup = false;
 113    /**
 114     * Package type local|url
 115     * @var string
 116     */
 117    var $_type;
 118    /**
 119     * Contents of package.xml, if downloaded from a remote channel
 120     * @var string|false
 121     * @access private
 122     */
 123    var $_rawpackagefile;
 124    /**
 125     * @var boolean
 126     * @access private
 127     */
 128    var $_validated = false;
 129
 130    /**
 131     * @param PEAR_Downloader
 132     */
 133    function PEAR_Downloader_Package(&$downloader)
 134    {
 135        $this->_downloader = &$downloader;
 136        $this->_config = &$this->_downloader->config;
 137        $this->_registry = &$this->_config->getRegistry();
 138        $options = $downloader->getOptions();
 139        if (isset($options['packagingroot'])) {
 140            $this->_config->setInstallRoot($options['packagingroot']);
 141            $this->_installRegistry = &$this->_config->getRegistry();
 142            $this->_config->setInstallRoot(false);
 143        } else {
 144            $this->_installRegistry = &$this->_registry;
 145        }
 146        $this->_valid = $this->_analyzed = false;
 147    }
 148
 149    /**
 150     * Parse the input and determine whether this is a local file, a remote uri, or an
 151     * abstract package name.
 152     *
 153     * This is the heart of the PEAR_Downloader_Package(), and is used in
 154     * {@link PEAR_Downloader::download()}
 155     * @param string
 156     * @return bool|PEAR_Error
 157     */
 158    function initialize($param)
 159    {
 160        $origErr = $this->_fromFile($param);
 161        if ($this->_valid) {
 162            return true;
 163        }
 164
 165        $options = $this->_downloader->getOptions();
 166        if (isset($options['offline'])) {
 167            if (PEAR::isError($origErr) && !isset($options['soft'])) {
 168                foreach ($origErr->getUserInfo() as $userInfo) {
 169                    if (isset($userInfo['message'])) {
 170                        $this->_downloader->log(0, $userInfo['message']);
 171                    }
 172                }
 173
 174                $this->_downloader->log(0, $origErr->getMessage());
 175            }
 176
 177            return PEAR::raiseError('Cannot download non-local package "' . $param . '"');
 178        }
 179
 180        $err = $this->_fromUrl($param);
 181        if (PEAR::isError($err) || !$this->_valid) {
 182            if ($this->_type == 'url') {
 183                if (PEAR::isError($err) && !isset($options['soft'])) {
 184                    $this->_downloader->log(0, $err->getMessage());
 185                }
 186
 187                return PEAR::raiseError("Invalid or missing remote package file");
 188            }
 189
 190            $err = $this->_fromString($param);
 191            if (PEAR::isError($err) || !$this->_valid) {
 192                if (PEAR::isError($err) && $err->getCode() == PEAR_DOWNLOADER_PACKAGE_STATE) {
 193                    return false; // instruct the downloader to silently skip
 194                }
 195
 196                if (isset($this->_type) && $this->_type == 'local' && PEAR::isError($origErr)) {
 197                    if (is_array($origErr->getUserInfo())) {
 198                        foreach ($origErr->getUserInfo() as $err) {
 199                            if (is_array($err)) {
 200                                $err = $err['message'];
 201                            }
 202
 203                            if (!isset($options['soft'])) {
 204                                $this->_downloader->log(0, $err);
 205                            }
 206                        }
 207                    }
 208
 209                    if (!isset($options['soft'])) {
 210                        $this->_downloader->log(0, $origErr->getMessage());
 211                    }
 212
 213                    if (is_array($param)) {
 214                        $param = $this->_registry->parsedPackageNameToString($param, true);
 215                    }
 216
 217                    if (!isset($options['soft'])) {
 218                        $this->_downloader->log(2, "Cannot initialize '$param', invalid or missing package file");
 219                    }
 220
 221                    // Passing no message back - already logged above
 222                    return PEAR::raiseError();
 223                }
 224
 225                if (PEAR::isError($err) && !isset($options['soft'])) {
 226                    $this->_downloader->log(0, $err->getMessage());
 227                }
 228
 229                if (is_array($param)) {
 230                    $param = $this->_registry->parsedPackageNameToString($param, true);
 231                }
 232
 233                if (!isset($options['soft'])) {
 234                    $this->_downloader->log(2, "Cannot initialize '$param', invalid or missing package file");
 235                }
 236
 237                // Passing no message back - already logged above
 238                return PEAR::raiseError();
 239            }
 240        }
 241
 242        return true;
 243    }
 244
 245    /**
 246     * Retrieve any non-local packages
 247     * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|PEAR_Error
 248     */
 249    function &download()
 250    {
 251        if (isset($this->_packagefile)) {
 252            return $this->_packagefile;
 253        }
 254
 255        if (isset($this->_downloadURL['url'])) {
 256            $this->_isvalid = false;
 257            $info = $this->getParsedPackage();
 258            foreach ($info as $i => $p) {
 259                $info[$i] = strtolower($p);
 260            }
 261
 262            $err = $this->_fromUrl($this->_downloadURL['url'],
 263                $this->_registry->parsedPackageNameToString($this->_parsedname, true));
 264            $newinfo = $this->getParsedPackage();
 265            foreach ($newinfo as $i => $p) {
 266                $newinfo[$i] = strtolower($p);
 267            }
 268
 269            if ($info != $newinfo) {
 270                do {
 271                    if ($info['channel'] == 'pecl.php.net' && $newinfo['channel'] == 'pear.php.net') {
 272                        $info['channel'] = 'pear.php.net';
 273                        if ($info == $newinfo) {
 274                            // skip the channel check if a pecl package says it's a PEAR package
 275                            break;
 276                        }
 277                    }
 278                    if ($info['channel'] == 'pear.php.net' && $newinfo['channel'] == 'pecl.php.net') {
 279                        $info['channel'] = 'pecl.php.net';
 280                        if ($info == $newinfo) {
 281                            // skip the channel check if a pecl package says it's a PEAR package
 282                            break;
 283                        }
 284                    }
 285
 286                    return PEAR::raiseError('CRITICAL ERROR: We are ' .
 287                        $this->_registry->parsedPackageNameToString($info) . ', but the file ' .
 288                        'downloaded claims to be ' .
 289                        $this->_registry->parsedPackageNameToString($this->getParsedPackage()));
 290                } while (false);
 291            }
 292
 293            if (PEAR::isError($err) || !$this->_valid) {
 294                return $err;
 295            }
 296        }
 297
 298        $this->_type = 'local';
 299        return $this->_packagefile;
 300    }
 301
 302    function &getPackageFile()
 303    {
 304        return $this->_packagefile;
 305    }
 306
 307    function &getDownloader()
 308    {
 309        return $this->_downloader;
 310    }
 311
 312    function getType()
 313    {
 314        return $this->_type;
 315    }
 316
 317    /**
 318     * Like {@link initialize()}, but operates on a dependency
 319     */
 320    function fromDepURL($dep)
 321    {
 322        $this->_downloadURL = $dep;
 323        if (isset($dep['uri'])) {
 324            $options = $this->_downloader->getOptions();
 325            if (!extension_loaded("zlib") || isset($options['nocompress'])) {
 326                $ext = '.tar';
 327            } else {
 328                $ext = '.tgz';
 329            }
 330
 331            PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
 332            $err = $this->_fromUrl($dep['uri'] . $ext);
 333            PEAR::popErrorHandling();
 334            if (PEAR::isError($err)) {
 335                if (!isset($options['soft'])) {
 336                    $this->_downloader->log(0, $err->getMessage());
 337                }
 338
 339                return PEAR::raiseError('Invalid uri dependency "' . $dep['uri'] . $ext . '", ' .
 340                    'cannot download');
 341            }
 342        } else {
 343            $this->_parsedname =
 344                array(
 345                    'package' => $dep['info']->getPackage(),
 346                    'channel' => $dep['info']->getChannel(),
 347                    'version' => $dep['version']
 348                );
 349            if (!isset($dep['nodefault'])) {
 350                $this->_parsedname['group'] = 'default'; // download the default dependency group
 351                $this->_explicitGroup = false;
 352            }
 353
 354            $this->_rawpackagefile = $dep['raw'];
 355        }
 356    }
 357
 358    function detectDependencies($params)
 359    {
 360        $options = $this->_downloader->getOptions();
 361        if (isset($options['downloadonly'])) {
 362            return;
 363        }
 364
 365        if (isset($options['offline'])) {
 366            $this->_downloader->log(3, 'Skipping dependency download check, --offline specified');
 367            return;
 368        }
 369
 370        $pname = $this->getParsedPackage();
 371        if (!$pname) {
 372            return;
 373        }
 374
 375        $deps = $this->getDeps();
 376        if (!$deps) {
 377            return;
 378        }
 379
 380        if (isset($deps['required'])) { // package.xml 2.0
 381            return $this->_detect2($deps, $pname, $options, $params);
 382        }
 383
 384        return $this->_detect1($deps, $pname, $options, $params);
 385    }
 386
 387    function setValidated()
 388    {
 389        $this->_validated = true;
 390    }
 391
 392    function alreadyValidated()
 393    {
 394        return $this->_validated;
 395    }
 396
 397    /**
 398     * Remove packages to be downloaded that are already installed
 399     * @param array of PEAR_Downloader_Package objects
 400     * @static
 401     */
 402    function removeInstalled(&$params)
 403    {
 404        if (!isset($params[0])) {
 405            return;
 406        }
 407
 408        $options = $params[0]->_downloader->getOptions();
 409        if (!isset($options['downloadonly'])) {
 410            foreach ($params as $i => $param) {
 411                $package = $param->getPackage();
 412                $channel = $param->getChannel();
 413                // remove self if already installed with this version
 414                // this does not need any pecl magic - we only remove exact matches
 415                if ($param->_installRegistry->packageExists($package, $channel)) {
 416                    $packageVersion = $param->_installRegistry->packageInfo($package, 'version', $channel);
 417                    if (version_compare($packageVersion, $param->getVersion(), '==')) {
 418                        if (!isset($options['force'])) {
 419                            $info = $param->getParsedPackage();
 420                            unset($info['version']);
 421                            unset($info['state']);
 422                            if (!isset($options['soft'])) {
 423                                $param->_downloader->log(1, 'Skipping package "' .
 424                                    $param->getShortName() .
 425                                    '", already installed as version ' . $packageVersion);
 426                            }
 427                            $params[$i] = false;
 428                        }
 429                    } elseif (!isset($options['force']) && !isset($options['upgrade']) &&
 430                          !isset($options['soft'])) {
 431                        $info = $param->getParsedPackage();
 432                        $param->_downloader->log(1, 'Skipping package "' .
 433                            $param->getShortName() .
 434                            '", already installed as version ' . $packageVersion);
 435                        $params[$i] = false;
 436                    }
 437                }
 438            }
 439        }
 440
 441        PEAR_Downloader_Package::removeDuplicates($params);
 442    }
 443
 444    function _detect2($deps, $pname, $options, $params)
 445    {
 446        $this->_downloadDeps = array();
 447        $groupnotfound = false;
 448        foreach (array('package', 'subpackage') as $packagetype) {
 449            // get required dependency group
 450            if (isset($deps['required'][$packagetype])) {
 451                if (isset($deps['required'][$packagetype][0])) {
 452                    foreach ($deps['required'][$packagetype] as $dep) {
 453                        if (isset($dep['conflicts'])) {
 454                            // skip any package that this package conflicts with
 455                            continue;
 456                        }
 457                        $ret = $this->_detect2Dep($dep, $pname, 'required', $params);
 458                        if (is_array($ret)) {
 459                            $this->_downloadDeps[] = $ret;
 460                        } elseif (PEAR::isError($ret) && !isset($options['soft'])) {
 461                            $this->_downloader->log(0, $ret->getMessage());
 462                        }
 463                    }
 464                } else {
 465                    $dep = $deps['required'][$packagetype];
 466                    if (!isset($dep['conflicts'])) {
 467                        // skip any package that this package conflicts with
 468                        $ret = $this->_detect2Dep($dep, $pname, 'required', $params);
 469                        if (is_array($ret)) {
 470                            $this->_downloadDeps[] = $ret;
 471                        } elseif (PEAR::isError($ret) && !isset($options['soft'])) {
 472                            $this->_downloader->log(0, $ret->getMessage());
 473                        }
 474                    }
 475                }
 476            }
 477
 478            // get optional dependency group, if any
 479            if (isset($deps['optional'][$packagetype])) {
 480                $skipnames = array();
 481                if (!isset($deps['optional'][$packagetype][0])) {
 482                    $deps['optional'][$packagetype] = array($deps['optional'][$packagetype]);
 483                }
 484
 485                foreach ($deps['optional'][$packagetype] as $dep) {
 486                    $skip = false;
 487                    if (!isset($options['alldeps'])) {
 488                        $dep['package'] = $dep['name'];
 489                        if (!isset($options['soft'])) {
 490                            $this->_downloader->log(3, 'Notice: package "' .
 491                              $this->_registry->parsedPackageNameToString($this->getParsedPackage(),
 492                                    true) . '" optional dependency "' .
 493                                $this->_registry->parsedPackageNameToString(array('package' =>
 494                                    $dep['name'], 'channel' => 'pear.php.net'), true) .
 495                                '" will not be automatically downloaded');
 496                        }
 497                        $skipnames[] = $this->_registry->parsedPackageNameToString($dep, true);
 498                        $skip = true;
 499                        unset($dep['package']);
 500                    }
 501
 502                    $ret = $this->_detect2Dep($dep, $pname, 'optional', $params);
 503                    if (PEAR::isError($ret) && !isset($options['soft'])) {
 504                        $this->_downloader->log(0, $ret->getMessage());
 505                    }
 506
 507                    if (!$ret) {
 508                        $dep['package'] = $dep['name'];
 509                        $skip = count($skipnames) ?
 510                            $skipnames[count($skipnames) - 1] : '';
 511                        if ($skip ==
 512                              $this->_registry->parsedPackageNameToString($dep, true)) {
 513                            array_pop($skipnames);
 514                        }
 515                    }
 516
 517                    if (!$skip && is_array($ret)) {
 518                        $this->_downloadDeps[] = $ret;
 519                    }
 520                }
 521
 522                if (count($skipnames)) {
 523                    if (!isset($options['soft'])) {
 524                        $this->_downloader->log(1, 'Did not download optional dependencies: ' .
 525                            implode(', ', $skipnames) .
 526                            ', use --alldeps to download automatically');
 527                    }
 528                }
 529            }
 530
 531            // get requested dependency group, if any
 532            $groupname = $this->getGroup();
 533            $explicit  = $this->_explicitGroup;
 534            if (!$groupname) {
 535                if (!$this->canDefault()) {
 536                    continue;
 537                }
 538
 539                $groupname = 'default'; // try the default dependency group
 540            }
 541
 542            if ($groupnotfound) {
 543                continue;
 544            }
 545
 546            if (isset($deps['group'])) {
 547                if (isset($deps['group']['attribs'])) {
 548                    if (strtolower($deps['group']['attribs']['name']) == strtolower($groupname)) {
 549                        $group = $deps['group'];
 550                    } elseif ($explicit) {
 551                        if (!isset($options['soft'])) {
 552                            $this->_downloader->log(0, 'Warning: package "' .
 553                                $this->_registry->parsedPackageNameToString($pname, true) .
 554                                '" has no dependency ' . 'group named "' . $groupname . '"');
 555                        }
 556
 557                        $groupnotfound = true;
 558                        continue;
 559                    }
 560                } else {
 561                    $found = false;
 562                    foreach ($deps['group'] as $group) {
 563                        if (strtolower($group['attribs']['name']) == strtolower($groupname)) {
 564                            $found = true;
 565                            break;
 566                        }
 567                    }
 568
 569                    if (!$found) {
 570                        if ($explicit) {
 571                            if (!isset($options['soft'])) {
 572                                $this->_downloader->log(0, 'Warning: package "' .
 573                                    $this->_registry->parsedPackageNameToString($pname, true) .
 574                                    '" has no dependency ' . 'group named "' . $groupname . '"');
 575                            }
 576                        }
 577
 578                        $groupnotfound = true;
 579                        continue;
 580                    }
 581                }
 582            }
 583
 584            if (isset($group) && isset($group[$packagetype])) {
 585                if (isset($group[$packagetype][0])) {
 586                    foreach ($group[$packagetype] as $dep) {
 587                        $ret = $this->_detect2Dep($dep, $pname, 'dependency group "' .
 588                            $group['attribs']['name'] . '"', $params);
 589                        if (is_array($ret)) {
 590                            $this->_downloadDeps[] = $ret;
 591                        } elseif (PEAR::isError($ret) && !isset($options['soft'])) {
 592                            $this->_downloader->log(0, $ret->getMessage());
 593                        }
 594                    }
 595                } else {
 596                    $ret = $this->_detect2Dep($group[$packagetype], $pname,
 597                        'dependency group "' .
 598                        $group['attribs']['name'] . '"', $params);
 599                    if (is_array($ret)) {
 600                        $this->_downloadDeps[] = $ret;
 601                    } elseif (PEAR::isError($ret) && !isset($options['soft'])) {
 602                        $this->_downloader->log(0, $ret->getMessage());
 603                    }
 604                }
 605            }
 606        }
 607    }
 608
 609    function _detect2Dep($dep, $pname, $group, $params)
 610    {
 611        if (isset($dep['conflicts'])) {
 612            return true;
 613        }
 614
 615        $options = $this->_downloader->getOptions();
 616        if (isset($dep['uri'])) {
 617            return array('uri' => $dep['uri'], 'dep' => $dep);;
 618        }
 619
 620        $testdep = $dep;
 621        $testdep['package'] = $dep['name'];
 622        if (PEAR_Downloader_Package::willDownload($testdep, $params)) {
 623            $dep['package'] = $dep['name'];
 624            if (!isset($options['soft'])) {
 625                $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group .
 626                    ' dependency "' .
 627                    $this->_registry->parsedPackageNameToString($dep, true) .
 628                    '", will be installed');
 629            }
 630            return false;
 631        }
 632
 633        $options = $this->_downloader->getOptions();
 634        PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
 635        if ($this->_explicitState) {
 636            $pname['state'] = $this->_explicitState;
 637        }
 638
 639        $url = $this->_downloader->_getDepPackageDownloadUrl($dep, $pname);
 640        if (PEAR::isError($url)) {
 641            PEAR::popErrorHandling();
 642            return $url;
 643        }
 644
 645        $dep['package'] = $dep['name'];
 646        $ret = $this->_analyzeDownloadURL($url, 'dependency', $dep, $params, $group == 'optional' &&
 647            !isset($options['alldeps']), true);
 648        PEAR::popErrorHandling();
 649        if (PEAR::isError($ret)) {
 650            if (!isset($options['soft'])) {
 651                $this->_downloader->log(0, $ret->getMessage());
 652            }
 653
 654            return false;
 655        }
 656
 657        // check to see if a dep is already installed and is the same or newer
 658        if (!isset($dep['min']) && !isset($dep['max']) && !isset($dep['recommended'])) {
 659            $oper = 'has';
 660        } else {
 661            $oper = 'gt';
 662        }
 663
 664        // do not try to move this before getDepPackageDownloadURL
 665        // we can't determine whether upgrade is necessary until we know what
 666        // version would be downloaded
 667        if (!isset($options['force']) && $this->isInstalled($ret, $oper)) {
 668            $version = $this->_installRegistry->packageInfo($dep['name'], 'version', $dep['channel']);
 669            $dep['package'] = $dep['name'];
 670            if (!isset($options['soft'])) {
 671                $this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group .
 672                    ' dependency "' .
 673                $this->_registry->parsedPackageNameToString($dep, true) .
 674                    '" version ' . $url['version'] . ', already installed as version ' .
 675                    $version);
 676            }
 677
 678            return false;
 679        }
 680
 681        if (isset($dep['nodefault'])) {
 682            $ret['nodefault'] = true;
 683        }
 684
 685        return $ret;
 686    }
 687
 688    function _detect1($deps, $pname, $options, $params)
 689    {
 690        $this->_downloadDeps = array();
 691        $skipnames = array();
 692        foreach ($deps as $dep) {
 693            $nodownload = false;
 694            if (isset ($dep['type']) && $dep['type'] === 'pkg') {
 695                $dep['channel'] = 'pear.php.net';
 696                $dep['package'] = $dep['name'];
 697                switch ($dep['rel']) {
 698                    case 'not' :
 699                        continue 2;
 700                    case 'ge' :
 701                    case 'eq' :
 702                    case 'gt' :
 703                    case 'has' :
 704                        $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ?
 705                            'required' :
 706                            'optional';
 707                        if (PEAR_Downloader_Package::willDownload($dep, $params)) {
 708                            $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group
 709                                . ' dependency "' .
 710                                $this->_registry->parsedPackageNameToString($dep, true) .
 711                                '", will be installed');
 712                            continue 2;
 713                        }
 714                        $fakedp = new PEAR_PackageFile_v1;
 715                        $fakedp->setPackage($dep['name']);
 716                        // skip internet check if we are not upgrading (bug #5810)
 717                        if (!isset($options['upgrade']) && $this->isInstalled(
 718                              $fakedp, $dep['rel'])) {
 719                            $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group
 720                                . ' dependency "' .
 721                                $this->_registry->parsedPackageNameToString($dep, true) .
 722                                '", is already installed');
 723                            continue 2;
 724                        }
 725                }
 726
 727                PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
 728                if ($this->_explicitState) {
 729                    $pname['state'] = $this->_explicitState;
 730                }
 731
 732                $url = $this->_downloader->_getDepPackageDownloadUrl($dep, $pname);
 733                $chan = 'pear.php.net';
 734                if (PEAR::isError($url)) {
 735                    // check to see if this is a pecl package that has jumped
 736                    // from pear.php.net to pecl.php.net channel
 737                    if (!class_exists('PEAR_Dependency2')) {
 738                        require_once 'PEAR/Dependency2.php';
 739                    }
 740
 741                    $newdep = PEAR_Dependency2::normalizeDep($dep);
 742                    $newdep = $newdep[0];
 743                    $newdep['channel'] = 'pecl.php.net';
 744                    $chan = 'pecl.php.net';
 745                    $url = $this->_downloader->_getDepPackageDownloadUrl($newdep, $pname);
 746                    $obj = &$this->_installRegistry->getPackage($dep['name']);
 747                    if (PEAR::isError($url)) {
 748                        PEAR::popErrorHandling();
 749                        if ($obj !== null && $this->isInstalled($obj, $dep['rel'])) {
 750                            $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ?
 751                                'required' :
 752                                'optional';
 753                            $dep['package'] = $dep['name'];
 754                            if (!isset($options['soft'])) {
 755                                $this->_downloader->log(3, $this->getShortName() .
 756                                    ': Skipping ' . $group . ' dependency "' .
 757                                    $this->_registry->parsedPackageNameToString($dep, true) .
 758                                    '", already installed as version ' . $obj->getVersion());
 759                            }
 760                            $skip = count($skipnames) ?
 761                                $skipnames[count($skipnames) - 1] : '';
 762                            if ($skip ==
 763                                  $this->_registry->parsedPackageNameToString($dep, true)) {
 764                                array_pop($skipnames);
 765                            }
 766                            continue;
 767                        } else {
 768                            if (isset($dep['optional']) && $dep['optional'] == 'yes') {
 769                                $this->_downloader->log(2, $this->getShortName() .
 770                                    ': Skipping optional dependency "' .
 771                                    $this->_registry->parsedPackageNameToString($dep, true) .
 772                                    '", no releases exist');
 773                                continue;
 774                            } else {
 775                                return $url;
 776                            }
 777                        }
 778                    }
 779                }
 780
 781                PEAR::popErrorHandling();
 782                if (!isset($options['alldeps'])) {
 783                    if (isset($dep['optional']) && $dep['optional'] == 'yes') {
 784                        if (!isset($options['soft'])) {
 785                            $this->_downloader->log(3, 'Notice: package "' .
 786                                $this->getShortName() .
 787                                '" optional dependency "' .
 788                                $this->_registry->parsedPackageNameToString(
 789                                    array('channel' => $chan, 'package' =>
 790                                    $dep['name']), true) .
 791                                '" will not be automatically downloaded');
 792                        }
 793                        $skipnames[] = $this->_registry->parsedPackageNameToString(
 794                                array('channel' => $chan, 'package' =>
 795                                $dep['name']), true);
 796                        $nodownload = true;
 797                    }
 798                }
 799
 800                if (!isset($options['alldeps']) && !isset($options['onlyreqdeps'])) {
 801                    if (!isset($dep['optional']) || $dep['optional'] == 'no') {
 802                        if (!isset($options['soft'])) {
 803                            $this->_downloader->log(3, 'Notice: package "' .
 804                                $this->getShortName() .
 805                                '" required dependency "' .
 806                                $this->_registry->parsedPackageNameToString(
 807                                    array('channel' => $chan, 'package' =>
 808                                    $dep['name']), true) .
 809                                '" will not be automatically downloaded');
 810                        }
 811                        $skipnames[] = $this->_registry->parsedPackageNameToString(
 812                                array('channel' => $chan, 'package' =>
 813                                $dep['name']), true);
 814                        $nodownload = true;
 815                    }
 816                }
 817
 818                // check to see if a dep is already installed
 819                // do not try to move this before getDepPackageDownloadURL
 820                // we can't determine whether upgrade is necessary until we know what
 821                // version would be downloaded
 822                if (!isset($options['force']) && $this->isInstalled(
 823                        $url, $dep['rel'])) {
 824                    $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ?
 825                        'required' :
 826                        'optional';
 827                    $dep['package'] = $dep['name'];
 828                    if (isset($newdep)) {
 829                        $version = $this->_installRegistry->packageInfo($newdep['name'], 'version', $newdep['channel']);
 830                    } else {
 831                        $version = $this->_installRegistry->packageInfo($dep['name'], 'version');
 832                    }
 833
 834                    $dep['version'] = $url['version'];
 835                    if (!isset($options['soft'])) {
 836                        $this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group .
 837                            ' dependency "' .
 838                            $this->_registry->parsedPackageNameToString($dep, true) .
 839                            '", already installed as version ' . $version);
 840                    }
 841
 842                    $skip = count($skipnames) ?
 843                        $skipnames[count($skipnames) - 1] : '';
 844                    if ($skip ==
 845                          $this->_registry->parsedPackageNameToString($dep, true)) {
 846                        array_pop($skipnames);
 847                    }
 848
 849                    continue;
 850                }
 851
 852                if ($nodownload) {
 853                    continue;
 854                }
 855
 856                PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
 857                if (isset($newdep)) {
 858                    $dep = $newdep;
 859                }
 860
 861                $dep['package'] = $dep['name'];
 862                $ret = $this->_analyzeDownloadURL($url, 'dependency', $dep, $params,
 863                    isset($dep['optional']) && $dep['optional'] == 'yes' &&
 864                    !isset($options['alldeps']), true);
 865                PEAR::popErrorHandling();
 866                if (PEAR::isError($ret)) {
 867                    if (!isset($options['soft'])) {
 868                        $this->_downloader->log(0, $ret->getMessage());
 869                    }
 870                    continue;
 871                }
 872
 873                $this->_downloadDeps[] = $ret;
 874            }
 875        }
 876
 877        if (count($skipnames)) {
 878            if (!isset($options['soft'])) {
 879                $this->_downloader->log(1, 'Did not download dependencies: ' .
 880                    implode(', ', $skipnames) .
 881                    ', use --alldeps or --onlyreqdeps to download automatically');
 882            }
 883        }
 884    }
 885
 886    function setDownloadURL($pkg)
 887    {
 888        $this->_downloadURL = $pkg;
 889    }
 890
 891    /**
 892     * Set the package.xml object for this downloaded package
 893     *
 894     * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 $pkg
 895     */
 896    function setPackageFile(&$pkg)
 897    {
 898        $this->_packagefile = &$pkg;
 899    }
 900
 901    function getShortName()
 902    {
 903        return $this->_registry->parsedPackageNameToString(array('channel' => $this->getChannel(),
 904            'package' => $this->getPackage()), true);
 905    }
 906
 907    function getParsedPackage()
 908    {
 909        if (isset($this->_packagefile) || isset($this->_parsedname)) {
 910            return array('channel' => $this->getChannel(),
 911                'package' => $this->getPackage(),
 912                'version' => $this->getVersion());
 913        }
 914
 915        return false;
 916    }
 917
 918    function getDownloadURL()
 919    {
 920        return $this->_downloadURL;
 921    }
 922
 923    function canDefault()
 924    {
 925        if (isset($this->_downloadURL) && isset($this->_downloadURL['nodefault'])) {
 926            return false;
 927        }
 928
 929        return true;
 930    }
 931
 932    function getPackage()
 933    {
 934        if (isset($this->_packagefile)) {
 935            return $this->_packagefile->getPackage();
 936        } elseif (isset($this->_downloadURL['info'])) {
 937            return $this->_downloadURL['info']->getPackage();
 938        }
 939
 940        return false;
 941    }
 942
 943    /**
 944     * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
 945     */
 946    function isSubpackage(&$pf)
 947    {
 948        if (isset($this->_packagefile)) {
 949            return $this->_packagefile->isSubpackage($pf);
 950        } elseif (isset($this->_downloadURL['info'])) {
 951            return $this->_downloadURL['info']->isSubpackage($pf);
 952        }
 953
 954        return false;
 955    }
 956
 957    function getPackageType()
 958    {
 959        if (isset($this->_packagefile)) {
 960            return $this->_packagefile->getPackageType();
 961        } elseif (isset($this->_downloadURL['info'])) {
 962            return $this->_downloadURL['info']->getPackageType();
 963        }
 964
 965        return false;
 966    }
 967
 968    function isBundle()
 969    {
 970        if (isset($this->_packagefile)) {
 971            return $this->_packagefile->getPackageType() == 'bundle';
 972        }
 973
 974        return false;
 975    }
 976
 977    function getPackageXmlVersion()
 978    {
 979        if (isset($this->_packagefile)) {
 980            return $this->_packagefile->getPackagexmlVersion();
 981        } elseif (isset($this->_downloadURL['info'])) {
 982            return $this->_downloadURL['info']->getPackagexmlVersion();
 983        }
 984
 985        return '1.0';
 986    }
 987
 988    function getChannel()
 989    {
 990        if (isset($this->_packagefile)) {
 991            return $this->_packagefile->getChannel();
 992        } elseif (isset($this->_downloadURL['info'])) {
 993            return $this->_downloadURL['info']->getChannel();
 994        }
 995
 996        return false;
 997    }
 998
 999    function getURI()
1000    {
1001        if (isset($this->_packagefile)) {
1002            return $this->_packagefile->getURI();
1003        } elseif (isset($this->_downloadURL['info'])) {
1004            return $this->_downloadURL['info']->getURI();
1005        }
1006
1007        return false;
1008    }
1009
1010    function getVersion()
1011    {
1012        if (isset($this->_packagefile)) {
1013            return $this->_packagefile->getVersion();
1014        } elseif (isset($this->_downloadURL['version'])) {
1015            return $this->_downloadURL['version'];
1016        }
1017
1018        return false;
1019    }
1020
1021    function isCompatible($pf)
1022    {
1023        if (isset($this->_packagefile)) {
1024            return $this->_packagefile->isCompatible($pf);
1025        } elseif (isset($this->_downloadURL['info'])) {
1026            return $this->_downloadURL['info']->isCompatible($pf);
1027        }
1028
1029        return true;
1030    }
1031
1032    function setGroup($group)
1033    {
1034        $this->_parsedname['group'] = $group;
1035    }
1036
1037    function getGroup()
1038    {
1039        if (isset($this->_parsedname['group'])) {
1040            return $this->_parsedname['group'];
1041        }
1042
1043        return '';
1044    }
1045
1046    function isExtension($name)
1047    {
1048        if (isset($this->_packagefile)) {
1049            return $this->_packagefile->isExtension($name);
1050        } elseif (isset($this->_downloadURL['info'])) {
1051            if ($this->_downloadURL['info']->getPackagexmlVersion() == '2.0') {
1052                return $this->_downloadURL['info']->getProvidesExtension() == $name;
1053            }
1054
1055            return false;
1056        }
1057
1058        return false;
1059    }
1060
1061    function getDeps()
1062    {
1063        if (isset($this->_packagefile)) {
1064            $ver = $this->_packagefile->getPackagexmlVersion();
1065            if (version_compare($ver, '2.0', '>=')) {
1066                return $this->_packagefile->getDeps(true);
1067            }
1068
1069            return $this->_packagefile->getDeps();
1070        } elseif (isset($this->_downloadURL['info'])) {
1071            $ver = $this->_downloadURL['info']->getPackagexmlVersion();
1072            if (version_compare($ver, '2.0', '>=')) {
1073                return $this->_downloadURL['info']->getDeps(true);
1074            }
1075
1076            return $this->_downloadURL['info']->getDeps();
1077        }
1078
1079        return array();
1080    }
1081
1082    /**
1083     * @param array Parsed array from {@link PEAR_Registry::parsePackageName()} or a dependency
1084     *                     returned from getDepDownloadURL()
1085     */
1086    function isEqual($param)
1087    {
1088        if (is_object($param)) {
1089            $channel = $param->getChannel();
1090            $package = $param->getPackage();
1091            if ($param->getURI()) {
1092                $param = array(
1093                    'channel' => $param->getChannel(),
1094                    'package' => $param->getPackage(),
1095                    'version' => $param->getVersion(),
1096                    'uri' => $param->getURI(),
1097                );
1098            } else {
1099                $param = array(
1100                    'channel' => $param->getChannel(),
1101                    'package' => $param->getPackage(),
1102                    'version' => $param->getVersion(),
1103                );
1104            }
1105        } else {
1106            if (isset($param['uri'])) {
1107                if ($this->getChannel() != '__uri') {
1108                    return false;
1109                }
1110                return $param['uri'] == $this->getURI();
1111            }
1112
1113            $package = isset($param['package']) ? $param['package'] : $param['info']->getPackage();
1114            $channel = isset($param['channel']) ? $param['channel'] : $param['info']->getChannel();
1115            if (isset($param['rel'])) {
1116                if (!class_exists('PEAR_Dependency2')) {
1117                    require_once 'PEAR/Dependency2.php';
1118                }
1119
1120                $newdep = PEAR_Dependency2::normalizeDep($param);
1121                $newdep = $newdep[0];
1122            } elseif (isset($param['min'])) {
1123                $newdep = $param;
1124            }
1125        }
1126
1127        if (isset($newdep)) {
1128            if (!isset($newdep['min'])) {
1129                $newdep['min'] = '0';
1130            }
1131
1132            if (!isset($newdep['max'])) {
1133                $newdep['max'] = '100000000000000000000';
1134            }
1135
1136            // use magic to support pecl packages suddenly jumping to the pecl channel
1137            // we need to support both dependency possibilities
1138            if ($channel == 'pear.php.net' && $this->getChannel() == 'pecl.php.net') {
1139                if ($package == $this->getPackage()) {
1140                    $channel = 'pecl.php.net';
1141                }
1142            }
1143            if ($channel == 'pecl.php.net' && $this->getChannel() == 'pear.php.net') {
1144                if ($package == $this->getPackage()) {
1145                    $channel = 'pear.php.net';
1146                }
1147            }
1148
1149            return (strtolower($package) == strtolower($this->getPackage()) &&
1150                $channel == $this->getChannel() &&
1151                version_compare($newdep['min'], $this->getVersion(), '<=') &&
1152                version_compare($newdep['max'], $this->getVersion(), '>='));
1153        }
1154
1155        // use magic to support pecl packages suddenly jumping to the pecl channel
1156        if ($channel == 'pecl.php.net' && $this->getChannel() == 'pear.php.net') {
1157            if (strtolower($package) == strtolower($this->getPackage())) {
1158                $channel = 'pear.php.net';
1159            }
1160        }
1161
1162        if (isset($param['version'])) {
1163            return (strtolower($package) == strtolower($this->getPackage()) &&
1164                $channel == $this->getChannel() &&
1165                $param['version'] == $this->getVersion());
1166        }
1167
1168        return strtolower($package) == strtolower($this->getPackage()) &&
1169            $channel == $this->getChannel();
1170    }
1171
1172    function isInstalled($dep, $oper = '==')
1173    {
1174        if (!$dep) {
1175            return false;
1176        }
1177
1178        if ($oper != 'ge' && $oper != 'gt' && $oper != 'has' && $oper != '==') {
1179            return false;
1180        }
1181
1182        if (is_object($dep)) {
1183            $package = $dep->getPackage();
1184            $channel = $dep->getChannel();
1185            if ($dep->getURI()) {
1186                $dep = array(
1187                    'uri' => $dep->getURI(),
1188                    'version' => $dep->getVersion(),
1189                );
1190            } else {
1191                $dep = array(
1192                    'version' => $dep->getVersion(),
1193                );
1194            }
1195        } else {
1196            if (isset($dep['uri'])) {
1197                $channel = '__uri';
1198                $package = $dep['dep']['name'];
1199            } else {
1200                $channel = $dep['info']->getChannel();
1201                $package = $dep['info']->getPackage();
1202            }
1203        }
1204
1205        $options = $this->_downloader->getOptions();
1206        $test    = $this->_installRegistry->packageExists($package, $channel);
1207        if (!$test && $channel == 'pecl.php.net') {
1208            // do magic to allow upgrading from old pecl packages to new ones
1209            $test = $this->_installRegistry->packageExists($package, 'pear.php.net');
1210            $channel = 'pear.php.net';
1211        }
1212
1213        if ($test) {
1214            if (isset($dep['uri'])) {
1215                if ($this->_installRegistry->packageInfo($package, 'uri', '__uri') == $dep['uri']) {
1216                    return true;
1217                }
1218            }
1219
1220            if (isset($options['upgrade'])) {
1221                $packageVersion = $this->_installRegistry->packageInfo($package, 'version', $channel);
1222                if (version_compare($packageVersion, $dep['version'], '>=')) {
1223                    return true;
1224                }
1225
1226                return false;
1227            }
1228
1229            return true;
1230        }
1231
1232        return false;
1233    }
1234
1235    /**
1236     * Detect duplicate package names with differing versions
1237     *
1238     * If a user requests to install Date 1.4.6 and Date 1.4.7,
1239     * for instance, this is a logic error.  This method
1240     * detects this situation.
1241     *
1242     * @param array $params array of PEAR_Downloader_Package objects
1243     * @param array $errorparams empty array
1244     * @return array array of stupid duplicated packages in PEAR_Downloader_Package obejcts
1245     */
1246    function detectStupidDuplicates($params, &$errorparams)
1247    {
1248        $existing = array();
1249        foreach ($params as $i => $param) {
1250            $package = $param->getPackage();
1251            $channel = $param->getChannel();
1252            $group   = $param->getGroup();
1253            if (!isset($existing[$channel . '/' . $package])) {
1254                $existing[$channel . '/' . $package] = array();
1255            }
1256
1257            if (!isset($existing[$channel . '/' . $package][$group])) {
1258                $existing[$channel . '/' . $package][$group] = array();
1259            }
1260
1261            $existing[$channel . '/' . $package][$group][] = $i;
1262        }
1263
1264        $indices = array();
1265        foreach ($existing as $package => $groups) {
1266            foreach ($groups as $group => $dupes) {
1267                if (count($dupes) > 1) {
1268                    $indices = $indices + $dupes;
1269                }
1270            }
1271        }
1272
1273        $indices = array_unique($indices);
1274        foreach ($indices as $index) {
1275            $errorparams[] = $params[$index];
1276        }
1277
1278        return count($errorparams);
1279    }
1280
1281    /**
1282     * @param array
1283     * @param bool ignore install groups - for final removal of dupe packages
1284     * @static
1285     */
1286    function removeDuplicates(&$params, $ignoreGroups = false)
1287    {
1288        $pnames = array();
1289        foreach ($params as $i => $param) {
1290            if (!$param) {
1291                continue;
1292            }
1293
1294            if ($param->getPackage()) {
1295                $group = $ignoreGroups ? '' : $param->getGroup();
1296                $pnames[$i] = $param->getChannel() . '/' .
1297                    $param->getPackage() . '-' . $param->getVersion() . '#' . $group;
1298            }
1299        }
1300
1301        $pnames = array_unique($pnames);
1302        $unset  = array_diff(array_keys($params), array_keys($pnames));
1303        $testp  = array_flip($pnames);
1304        foreach ($params as $i => $param) {
1305            if (!$param) {
1306                $unset[] = $i;
1307                continue;
1308            }
1309
1310            if (!is_a($param, 'PEAR_Downloader_Package')) {
1311                $unset[] = $i;
1312                continue;
1313            }
1314
1315            $group = $ignoreGroups ? '' : $param->getGroup();
1316            if (!isset($testp[$param->getChannel() . '/' . $param->getPackage() . '-' .
1317                  $param->getVersion() . '#' . $group])) {
1318                $unset[] = $i;
1319            }
1320        }
1321
1322        foreach ($unset as $i) {
1323            unset($params[$i]);
1324        }
1325
1326        $ret = array();
1327        foreach ($params as $i => $param) {
1328            $ret[] = &$params[$i];
1329        }
1330
1331        $params = array();
1332        foreach ($ret as $i => $param) {
1333            $params[] = &$ret[$i];
1334        }
1335    }
1336
1337    function explicitState()
1338    {
1339        return $this->_explicitState;
1340    }
1341
1342    function setExplicitState($s)
1343    {
1344        $this->_explicitState = $s;
1345    }
1346
1347    /**
1348     * @static
1349     */
1350    function mergeDependencies(&$params)
1351    {
1352        $bundles = $newparams = array();
1353        foreach ($params as $i => $param) {
1354            if (!$param->isBundle()) {
1355                continue;
1356            }
1357
1358            $bundles[] = $i;
1359            $pf = &$param->getPackageFile();
1360            $newdeps = array();
1361            $contents = $pf->getBundledPackages();
1362            if (!is_array($contents)) {
1363                $contents = array($contents);
1364            }
1365
1366            foreach ($contents as $file) {
1367                $filecontents = $pf->getFileContents($file);
1368                $dl = &$param->getDownloader();
1369                $options = $dl->getOptions();
1370                if (PEAR::isError($dir = $dl->getDownloadDir())) {
1371                    return $dir;
1372                }
1373
1374                $fp = @fopen($dir . DIRECTORY_SEPARATOR . $file, 'wb');
1375                if (!$fp) {
1376                    continue;
1377                }
1378
1379                // FIXME do symlink check
1380
1381                fwrite($fp, $filecontents, strlen($filecontents));
1382                fclose($fp);
1383                if ($s = $params[$i]->explicitState()) {
1384                    $obj->setExplicitState($s);
1385                

Large files files are truncated, but you can click here to view the full file