3  * PEAR_Common, the base class for the PEAR Installer
 
   9  * @author     Stig Bakken <ssb@php.net>
 
  10  * @author     Tomas V. V. Cox <cox@idecnet.com>
 
  11  * @author     Greg Beaver <cellog@php.net>
 
  12  * @copyright  1997-2009 The Authors
 
  13  * @license    http://opensource.org/licenses/bsd-license.php New BSD License
 
  14  * @link       http://pear.php.net/package/PEAR
 
  15  * @since      File available since Release 0.1.0
 
  16  * @deprecated File deprecated since Release 1.4.0a1
 
  20  * Include error handling
 
  22 require_once 'PEAR.php';
 
  25  * PEAR_Common error when an invalid PHP file is passed to PEAR_Common::analyzeSourceCode()
 
  27 define('PEAR_COMMON_ERROR_INVALIDPHP', 1);
 
  28 define('_PEAR_COMMON_PACKAGE_NAME_PREG', '[A-Za-z][a-zA-Z0-9_]+');
 
  29 define('PEAR_COMMON_PACKAGE_NAME_PREG', '/^' . _PEAR_COMMON_PACKAGE_NAME_PREG . '\\z/');
 
  31 // this should allow: 1, 1.0, 1.0RC1, 1.0dev, 1.0dev123234234234, 1.0a1, 1.0b1, 1.0pl1
 
  32 define('_PEAR_COMMON_PACKAGE_VERSION_PREG', '\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?');
 
  33 define('PEAR_COMMON_PACKAGE_VERSION_PREG', '/^' . _PEAR_COMMON_PACKAGE_VERSION_PREG . '\\z/i');
 
  35 // XXX far from perfect :-)
 
  36 define('_PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '(' . _PEAR_COMMON_PACKAGE_NAME_PREG .
 
  37     ')(-([.0-9a-zA-Z]+))?');
 
  38 define('PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_PACKAGE_DOWNLOAD_PREG .
 
  41 define('_PEAR_CHANNELS_NAME_PREG', '[A-Za-z][a-zA-Z0-9\.]+');
 
  42 define('PEAR_CHANNELS_NAME_PREG', '/^' . _PEAR_CHANNELS_NAME_PREG . '\\z/');
 
  44 // this should allow any dns or IP address, plus a path - NO UNDERSCORES ALLOWED
 
  45 define('_PEAR_CHANNELS_SERVER_PREG', '[a-zA-Z0-9\-]+(?:\.[a-zA-Z0-9\-]+)*(\/[a-zA-Z0-9\-]+)*');
 
  46 define('PEAR_CHANNELS_SERVER_PREG', '/^' . _PEAR_CHANNELS_SERVER_PREG . '\\z/i');
 
  48 define('_PEAR_CHANNELS_PACKAGE_PREG',  '(' ._PEAR_CHANNELS_SERVER_PREG . ')\/('
 
  49          . _PEAR_COMMON_PACKAGE_NAME_PREG . ')');
 
  50 define('PEAR_CHANNELS_PACKAGE_PREG', '/^' . _PEAR_CHANNELS_PACKAGE_PREG . '\\z/i');
 
  52 define('_PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '(' . _PEAR_CHANNELS_NAME_PREG . ')::('
 
  53     . _PEAR_COMMON_PACKAGE_NAME_PREG . ')(-([.0-9a-zA-Z]+))?');
 
  54 define('PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_CHANNEL_DOWNLOAD_PREG . '\\z/');
 
  57  * List of temporary files and directories registered by
 
  58  * PEAR_Common::addTempFile().
 
  61 $GLOBALS['_PEAR_Common_tempfiles'] = array();
 
  64  * Valid maintainer roles
 
  67 $GLOBALS['_PEAR_Common_maintainer_roles'] = array('lead','developer','contributor','helper');
 
  70  * Valid release states
 
  73 $GLOBALS['_PEAR_Common_release_states'] = array('alpha','beta','stable','snapshot','devel');
 
  76  * Valid dependency types
 
  79 $GLOBALS['_PEAR_Common_dependency_types'] = array('pkg','ext','php','prog','ldlib','rtlib','os','websrv','sapi');
 
  82  * Valid dependency relations
 
  85 $GLOBALS['_PEAR_Common_dependency_relations'] = array('has','eq','lt','le','gt','ge','not', 'ne');
 
  91 $GLOBALS['_PEAR_Common_file_roles'] = array('php','ext','test','doc','data','src','script');
 
  94  * Valid replacement types
 
  97 $GLOBALS['_PEAR_Common_replacement_types'] = array('php-const', 'pear-config', 'package-info');
 
 100  * Valid "provide" types
 
 103 $GLOBALS['_PEAR_Common_provide_types'] = array('ext', 'prog', 'class', 'function', 'feature', 'api');
 
 106  * Valid "provide" types
 
 109 $GLOBALS['_PEAR_Common_script_phases'] = array('pre-install', 'post-install', 'pre-uninstall', 'post-uninstall', 'pre-build', 'post-build', 'pre-configure', 'post-configure', 'pre-setup', 'post-setup');
 
 112  * Class providing common functionality for PEAR administration classes.
 
 115  * @author     Stig Bakken <ssb@php.net>
 
 116  * @author     Tomas V. V. Cox <cox@idecnet.com>
 
 117  * @author     Greg Beaver <cellog@php.net>
 
 118  * @copyright  1997-2009 The Authors
 
 119  * @license    http://opensource.org/licenses/bsd-license.php New BSD License
 
 120  * @version    Release: 1.10.1
 
 121  * @link       http://pear.php.net/package/PEAR
 
 122  * @since      Class available since Release 1.4.0a1
 
 123  * @deprecated This class will disappear, and its components will be spread
 
 124  *             into smaller classes, like the AT&T breakup, as of Release 1.4.0a1
 
 126 class PEAR_Common extends PEAR
 
 129      * User Interface object (PEAR_Frontend_* class).  If null,
 
 130      * the log() method uses print.
 
 136      * Configuration object (PEAR_Config).
 
 141     /** stack of elements, gives some sort of XML context */
 
 142     var $element_stack = array();
 
 144     /** name of currently parsed XML element */
 
 145     var $current_element;
 
 147     /** array of attributes of the currently parsed XML element */
 
 148     var $current_attributes = array();
 
 150     /** assoc with information about a package */
 
 151     var $pkginfo = array();
 
 153     var $current_path = null;
 
 156      * Flag variable used to mark a valid package file
 
 160     var $_validPackageFile;
 
 163      * PEAR_Common constructor
 
 167     function __construct()
 
 169         parent::__construct();
 
 170         $this->config = &PEAR_Config::singleton();
 
 171         $this->debug = $this->config->get('verbose');
 
 175      * PEAR_Common destructor
 
 179     function _PEAR_Common()
 
 181         // doesn't work due to bug #14744
 
 182         //$tempfiles = $this->_tempfiles;
 
 183         $tempfiles =& $GLOBALS['_PEAR_Common_tempfiles'];
 
 184         while ($file = array_shift($tempfiles)) {
 
 185             if (@is_dir($file)) {
 
 186                 if (!class_exists('System')) {
 
 187                     require_once 'System.php';
 
 190                 System::rm(array('-rf', $file));
 
 191             } elseif (file_exists($file)) {
 
 198      * Register a temporary file or directory.  When the destructor is
 
 199      * executed, all registered temporary files and directories are
 
 202      * @param string  $file  name of file or directory
 
 208     function addTempFile($file)
 
 210         if (!class_exists('PEAR_Frontend')) {
 
 211             require_once 'PEAR/Frontend.php';
 
 213         PEAR_Frontend::addTempFile($file);
 
 217      * Wrapper to System::mkDir(), creates a directory as well as
 
 218      * any necessary parent directories.
 
 220      * @param string  $dir  directory name
 
 222      * @return bool TRUE on success, or a PEAR error
 
 226     function mkDirHier($dir)
 
 228         // Only used in Installer - move it there ?
 
 229         $this->log(2, "+ create dir $dir");
 
 230         if (!class_exists('System')) {
 
 231             require_once 'System.php';
 
 233         return System::mkDir(array('-p', $dir));
 
 239      * @param int    $level  log level (0 is quiet, higher is noisier)
 
 240      * @param string $msg    message to write to the log
 
 244     public function log($level, $msg, $append_crlf = true)
 
 246         if ($this->debug >= $level) {
 
 247             if (!class_exists('PEAR_Frontend')) {
 
 248                 require_once 'PEAR/Frontend.php';
 
 251             $ui = &PEAR_Frontend::singleton();
 
 252             if (is_a($ui, 'PEAR_Frontend')) {
 
 253                 $ui->log($msg, $append_crlf);
 
 261      * Create and register a temporary directory.
 
 263      * @param string $tmpdir (optional) Directory to use as tmpdir.
 
 264      *                       Will use system defaults (for example
 
 265      *                       /tmp or c:\windows\temp) if not specified
 
 267      * @return string name of created directory
 
 271     function mkTempDir($tmpdir = '')
 
 273         $topt = $tmpdir ? array('-t', $tmpdir) : array();
 
 274         $topt = array_merge($topt, array('-d', 'pear'));
 
 275         if (!class_exists('System')) {
 
 276             require_once 'System.php';
 
 279         if (!$tmpdir = System::mktemp($topt)) {
 
 283         $this->addTempFile($tmpdir);
 
 288      * Set object that represents the frontend to be used.
 
 290      * @param  object Reference of the frontend object
 
 294     function setFrontendObject(&$ui)
 
 300      * Return an array containing all of the states that are more stable than
 
 301      * or equal to the passed in state
 
 303      * @param string Release state
 
 304      * @param boolean Determines whether to include $state in the list
 
 305      * @return false|array False if $state is not a valid release state
 
 307     function betterStates($state, $include = false)
 
 309         static $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable');
 
 310         $i = array_search($state, $states);
 
 317         return array_slice($states, $i + 1);
 
 321      * Get the valid roles for a PEAR package maintainer
 
 325     public static function getUserRoles()
 
 327         return $GLOBALS['_PEAR_Common_maintainer_roles'];
 
 331      * Get the valid package release states of packages
 
 335     public static function getReleaseStates()
 
 337         return $GLOBALS['_PEAR_Common_release_states'];
 
 341      * Get the implemented dependency types (php, ext, pkg etc.)
 
 345     public static function getDependencyTypes()
 
 347         return $GLOBALS['_PEAR_Common_dependency_types'];
 
 351      * Get the implemented dependency relations (has, lt, ge etc.)
 
 355     public static function getDependencyRelations()
 
 357         return $GLOBALS['_PEAR_Common_dependency_relations'];
 
 361      * Get the implemented file roles
 
 365     public static function getFileRoles()
 
 367         return $GLOBALS['_PEAR_Common_file_roles'];
 
 371      * Get the implemented file replacement types in
 
 375     public static function getReplacementTypes()
 
 377         return $GLOBALS['_PEAR_Common_replacement_types'];
 
 381      * Get the implemented file replacement types in
 
 385     public static function getProvideTypes()
 
 387         return $GLOBALS['_PEAR_Common_provide_types'];
 
 391      * Get the implemented file replacement types in
 
 395     public static function getScriptPhases()
 
 397         return $GLOBALS['_PEAR_Common_script_phases'];
 
 401      * Test whether a string contains a valid package name.
 
 403      * @param string $name the package name to test
 
 409     function validPackageName($name)
 
 411         return (bool)preg_match(PEAR_COMMON_PACKAGE_NAME_PREG, $name);
 
 415      * Test whether a string contains a valid package version.
 
 417      * @param string $ver the package version to test
 
 423     function validPackageVersion($ver)
 
 425         return (bool)preg_match(PEAR_COMMON_PACKAGE_VERSION_PREG, $ver);
 
 429      * @param string $path relative or absolute include path
 
 432     public static function isIncludeable($path)
 
 434         if (file_exists($path) && is_readable($path)) {
 
 438         $ipath = explode(PATH_SEPARATOR, ini_get('include_path'));
 
 439         foreach ($ipath as $include) {
 
 440             $test = realpath($include . DIRECTORY_SEPARATOR . $path);
 
 441             if (file_exists($test) && is_readable($test)) {
 
 449     function _postProcessChecks($pf)
 
 451         if (!PEAR::isError($pf)) {
 
 452             return $this->_postProcessValidPackagexml($pf);
 
 455         $errs = $pf->getUserinfo();
 
 456         if (is_array($errs)) {
 
 457             foreach ($errs as $error) {
 
 458                 $e = $this->raiseError($error['message'], $error['code'], null, null, $error);
 
 466      * Returns information about a package file.  Expects the name of
 
 467      * a gzipped tar file as input.
 
 469      * @param string  $file  name of .tgz file
 
 471      * @return array  array with package information
 
 474      * @deprecated use PEAR_PackageFile->fromTgzFile() instead
 
 477     function infoFromTgzFile($file)
 
 479         $packagefile = new PEAR_PackageFile($this->config);
 
 480         $pf = &$packagefile->fromTgzFile($file, PEAR_VALIDATE_NORMAL);
 
 481         return $this->_postProcessChecks($pf);
 
 485      * Returns information about a package file.  Expects the name of
 
 486      * a package xml file as input.
 
 488      * @param string  $descfile  name of package xml file
 
 490      * @return array  array with package information
 
 493      * @deprecated use PEAR_PackageFile->fromPackageFile() instead
 
 496     function infoFromDescriptionFile($descfile)
 
 498         $packagefile = new PEAR_PackageFile($this->config);
 
 499         $pf = &$packagefile->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL);
 
 500         return $this->_postProcessChecks($pf);
 
 504      * Returns information about a package file.  Expects the contents
 
 505      * of a package xml file as input.
 
 507      * @param string  $data  contents of package.xml file
 
 509      * @return array   array with package information
 
 512      * @deprecated use PEAR_PackageFile->fromXmlstring() instead
 
 515     function infoFromString($data)
 
 517         $packagefile = new PEAR_PackageFile($this->config);
 
 518         $pf = &$packagefile->fromXmlString($data, PEAR_VALIDATE_NORMAL, false);
 
 519         return $this->_postProcessChecks($pf);
 
 523      * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
 
 526     function _postProcessValidPackagexml(&$pf)
 
 528         if (!is_a($pf, 'PEAR_PackageFile_v2')) {
 
 529             $this->pkginfo = $pf->toArray();
 
 530             return $this->pkginfo;
 
 533         // sort of make this into a package.xml 1.0-style array
 
 534         // changelog is not converted to old format.
 
 535         $arr = $pf->toArray(true);
 
 536         $arr = array_merge($arr, $arr['old']);
 
 537         unset($arr['old'], $arr['xsdversion'], $arr['contents'], $arr['compatible'],
 
 538               $arr['channel'], $arr['uri'], $arr['dependencies'], $arr['phprelease'],
 
 539               $arr['extsrcrelease'], $arr['zendextsrcrelease'], $arr['extbinrelease'],
 
 540               $arr['zendextbinrelease'], $arr['bundle'], $arr['lead'], $arr['developer'],
 
 541               $arr['helper'], $arr['contributor']);
 
 542         $arr['filelist'] = $pf->getFilelist();
 
 543         $this->pkginfo = $arr;
 
 548      * Returns package information from different sources
 
 550      * This method is able to extract information about a package
 
 551      * from a .tgz archive or from a XML package definition file.
 
 554      * @param  string Filename of the source ('package.xml', '<package>.tgz')
 
 556      * @deprecated use PEAR_PackageFile->fromAnyFile() instead
 
 558     function infoFromAny($info)
 
 560         if (is_string($info) && file_exists($info)) {
 
 561             $packagefile = new PEAR_PackageFile($this->config);
 
 562             $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL);
 
 563             if (PEAR::isError($pf)) {
 
 564                 $errs = $pf->getUserinfo();
 
 565                 if (is_array($errs)) {
 
 566                     foreach ($errs as $error) {
 
 567                         $e = $this->raiseError($error['message'], $error['code'], null, null, $error);
 
 574             return $this->_postProcessValidPackagexml($pf);
 
 581      * Return an XML document based on the package info (as returned
 
 582      * by the PEAR_Common::infoFrom* methods).
 
 584      * @param array  $pkginfo  package info
 
 586      * @return string XML data
 
 589      * @deprecated use a PEAR_PackageFile_v* object's generator instead
 
 591     function xmlFromInfo($pkginfo)
 
 593         $config      = &PEAR_Config::singleton();
 
 594         $packagefile = new PEAR_PackageFile($config);
 
 595         $pf = &$packagefile->fromArray($pkginfo);
 
 596         $gen = &$pf->getDefaultGenerator();
 
 597         return $gen->toXml(PEAR_VALIDATE_PACKAGING);
 
 601      * Validate XML package definition file.
 
 603      * @param  string $info Filename of the package archive or of the
 
 604      *                package definition file
 
 605      * @param  array $errors Array that will contain the errors
 
 606      * @param  array $warnings Array that will contain the warnings
 
 607      * @param  string $dir_prefix (optional) directory where source files
 
 608      *                may be found, or empty if they are not available
 
 611      * @deprecated use the validation of PEAR_PackageFile objects
 
 613     function validatePackageInfo($info, &$errors, &$warnings, $dir_prefix = '')
 
 615         $config      = &PEAR_Config::singleton();
 
 616         $packagefile = new PEAR_PackageFile($config);
 
 617         PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
 
 618         if (strpos($info, '<?xml') !== false) {
 
 619             $pf = &$packagefile->fromXmlString($info, PEAR_VALIDATE_NORMAL, '');
 
 621             $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL);
 
 624         PEAR::staticPopErrorHandling();
 
 625         if (PEAR::isError($pf)) {
 
 626             $errs = $pf->getUserinfo();
 
 627             if (is_array($errs)) {
 
 628                 foreach ($errs as $error) {
 
 629                     if ($error['level'] == 'error') {
 
 630                         $errors[] = $error['message'];
 
 632                         $warnings[] = $error['message'];
 
 644      * Build a "provides" array from data returned by
 
 645      * analyzeSourceCode().  The format of the built array is like
 
 649      *    'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'),
 
 654      * @param array $srcinfo array with information about a source file
 
 655      * as returned by the analyzeSourceCode() method.
 
 662     function buildProvidesArray($srcinfo)
 
 664         $file = basename($srcinfo['source_file']);
 
 666         if (isset($this->_packageName)) {
 
 667             $pn = $this->_packageName;
 
 671         foreach ($srcinfo['declared_classes'] as $class) {
 
 672             $key = "class;$class";
 
 673             if (isset($this->pkginfo['provides'][$key])) {
 
 677             $this->pkginfo['provides'][$key] =
 
 678                 array('file'=> $file, 'type' => 'class', 'name' => $class);
 
 679             if (isset($srcinfo['inheritance'][$class])) {
 
 680                 $this->pkginfo['provides'][$key]['extends'] =
 
 681                     $srcinfo['inheritance'][$class];
 
 685         foreach ($srcinfo['declared_methods'] as $class => $methods) {
 
 686             foreach ($methods as $method) {
 
 687                 $function = "$class::$method";
 
 688                 $key = "function;$function";
 
 689                 if ($method{0} == '_' || !strcasecmp($method, $class) ||
 
 690                     isset($this->pkginfo['provides'][$key])) {
 
 694                 $this->pkginfo['provides'][$key] =
 
 695                     array('file'=> $file, 'type' => 'function', 'name' => $function);
 
 699         foreach ($srcinfo['declared_functions'] as $function) {
 
 700             $key = "function;$function";
 
 701             if ($function{0} == '_' || isset($this->pkginfo['provides'][$key])) {
 
 705             if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) {
 
 706                 $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\"";
 
 709             $this->pkginfo['provides'][$key] =
 
 710                 array('file'=> $file, 'type' => 'function', 'name' => $function);
 
 715      * Analyze the source code of the given PHP file
 
 717      * @param  string Filename of the PHP file
 
 721     function analyzeSourceCode($file)
 
 723         if (!class_exists('PEAR_PackageFile_v2_Validator')) {
 
 724             require_once 'PEAR/PackageFile/v2/Validator.php';
 
 727         $a = new PEAR_PackageFile_v2_Validator;
 
 728         return $a->analyzeSourceCode($file);
 
 731     function detectDependencies($any, $status_callback = null)
 
 733         if (!function_exists("token_get_all")) {
 
 737         if (PEAR::isError($info = $this->infoFromAny($any))) {
 
 738             return $this->raiseError($info);
 
 741         if (!is_array($info)) {
 
 746         $used_c = $decl_c = $decl_f = $decl_m = array();
 
 747         foreach ($info['filelist'] as $file => $fa) {
 
 748             $tmp = $this->analyzeSourceCode($file);
 
 749             $used_c = @array_merge($used_c, $tmp['used_classes']);
 
 750             $decl_c = @array_merge($decl_c, $tmp['declared_classes']);
 
 751             $decl_f = @array_merge($decl_f, $tmp['declared_functions']);
 
 752             $decl_m = @array_merge($decl_m, $tmp['declared_methods']);
 
 753             $inheri = @array_merge($inheri, $tmp['inheritance']);
 
 756         $used_c = array_unique($used_c);
 
 757         $decl_c = array_unique($decl_c);
 
 758         $undecl_c = array_diff($used_c, $decl_c);
 
 760         return array('used_classes' => $used_c,
 
 761                      'declared_classes' => $decl_c,
 
 762                      'declared_methods' => $decl_m,
 
 763                      'declared_functions' => $decl_f,
 
 764                      'undeclared_classes' => $undecl_c,
 
 765                      'inheritance' => $inheri,
 
 770      * Download a file through HTTP.  Considers suggested file name in
 
 771      * Content-disposition: header and can run a callback function for
 
 772      * different events.  The callback will be called with two
 
 773      * parameters: the callback type, and parameters.  The implemented
 
 774      * callback types are:
 
 776      *  'setup'       called at the very beginning, parameter is a UI object
 
 777      *                that should be used for all output
 
 778      *  'message'     the parameter is a string with an informational message
 
 779      *  'saveas'      may be used to save with a different file name, the
 
 780      *                parameter is the filename that is about to be used.
 
 781      *                If a 'saveas' callback returns a non-empty string,
 
 782      *                that file name will be used as the filename instead.
 
 783      *                Note that $save_dir will not be affected by this, only
 
 784      *                the basename of the file.
 
 785      *  'start'       download is starting, parameter is number of bytes
 
 786      *                that are expected, or -1 if unknown
 
 787      *  'bytesread'   parameter is the number of bytes read so far
 
 788      *  'done'        download is complete, parameter is the total number
 
 790      *  'connfailed'  if the TCP connection fails, this callback is called
 
 791      *                with array(host,port,errno,errmsg)
 
 792      *  'writefailed' if writing to disk fails, this callback is called
 
 793      *                with array(destfile,errmsg)
 
 795      * If an HTTP proxy has been configured (http_proxy PEAR_Config
 
 796      * setting), the proxy will be used.
 
 798      * @param string  $url       the URL to download
 
 799      * @param object  $ui        PEAR_Frontend_* instance
 
 800      * @param object  $config    PEAR_Config instance
 
 801      * @param string  $save_dir  (optional) directory to save file in
 
 802      * @param mixed   $callback  (optional) function/method to call for status
 
 804      * @param false|string|array $lastmodified header values to check against
 
 806      *                                         use false to return the header
 
 807      *                                         values from this download
 
 808      * @param false|array        $accept       Accept headers to send
 
 809      * @param false|string       $channel      Channel to use for retrieving
 
 812      * @return mixed  Returns the full path of the downloaded file or a PEAR
 
 813      *                error on failure.  If the error is caused by
 
 814      *                socket-related errors, the error object will
 
 815      *                have the fsockopen error code available through
 
 816      *                getCode().  If caching is requested, then return the header
 
 818      *                If $lastmodified was given and the there are no changes,
 
 819      *                boolean false is returned.
 
 823     function downloadHttp(
 
 824         $url, &$ui, $save_dir = '.', $callback = null, $lastmodified = null,
 
 825         $accept = false, $channel = false
 
 827         if (!class_exists('PEAR_Downloader')) {
 
 828             require_once 'PEAR/Downloader.php';
 
 830         return PEAR_Downloader::_downloadHttp(
 
 831             $this, $url, $ui, $save_dir, $callback, $lastmodified,
 
 837 require_once 'PEAR/Config.php';
 
 838 require_once 'PEAR/PackageFile.php';