From: Stig Bakken Date: Tue, 9 Apr 2002 18:04:33 +0000 (+0000) Subject: * partial PEAR MFH X-Git-Tag: php-4.2.0RC3~28 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=09d7728c0a344ea680c2228581dd90d64f9e96fa;p=php * partial PEAR MFH --- diff --git a/pear/DB.php b/pear/DB.php index 86125a2b60..22cff1f81c 100644 --- a/pear/DB.php +++ b/pear/DB.php @@ -261,6 +261,9 @@ class DB @$obj =& new $classname; + if (isset($options['connect_ondemand']) && !extension_loaded("overload")) { + unset($options['connect_ondemand']); + } if (is_array($options)) { foreach ($options as $option => $value) { $test = $obj->setOption($option, $value); @@ -271,11 +274,14 @@ class DB } else { $obj->setOption('persistent', $options); } - $err = $obj->connect($dsninfo, $obj->getOption('persistent')); - - if (DB::isError($err)) { - $err->addUserInfo($dsn); - return $err; + if (!$obj->getOption('connect_ondemand')) { + $err = $obj->connect($dsninfo, $obj->getOption('persistent')); + if (DB::isError($err)) { + $err->addUserInfo($dsn); + return $err; + } + } else { + $obj->dsn = $dsninfo; } return $obj; diff --git a/pear/Makefile.frag b/pear/Makefile.frag index 1395913117..18248215d7 100644 --- a/pear/Makefile.frag +++ b/pear/Makefile.frag @@ -1,7 +1,6 @@ -# -*- makefile -*- pear_install_targets = \ - install-pear \ + install-data-local \ install-headers \ install-build \ install-programs @@ -11,26 +10,63 @@ peardir=$(PEAR_INSTALLDIR) PEAR_SUBDIRS = \ Archive \ Console \ + Crypt \ + Date \ + DB \ + File \ + HTML \ + HTTP \ + Image \ + Mail \ + Net \ PEAR \ PEAR/Command \ PEAR/Frontend \ + Schedule \ XML -# These are moving to /pear (in cvs): -# Crypt \ -# File \ -# Date \ -# DB \ -# HTML \ -# HTTP \ -# Image \ -# Mail \ -# Net \ -# Schedule \ - PEAR_FILES = \ Archive/Tar.php \ Console/Getopt.php \ + Crypt/CBC.php \ + Crypt/HCEMD5.php \ + Date/Calc.php \ + Date/Human.php \ + DB.php \ + DB/common.php \ + DB/fbsql.php \ + DB/ibase.php \ + DB/ifx.php \ + DB/msql.php \ + DB/mssql.php \ + DB/mysql.php \ + DB/oci8.php \ + DB/odbc.php \ + DB/pgsql.php \ + DB/storage.php \ + DB/sybase.php \ + File/Find.php \ + File/Passwd.php \ + File/SearchReplace.php \ + HTML/Common.php \ + HTML/Form.php \ + HTML/IT.php \ + HTML/ITX.php \ + HTML/IT_Error.php \ + HTML/Page.php \ + HTML/Processor.php \ + HTML/Select.php \ + HTML/Table.php \ + HTTP.php \ + HTTP/Compress.php \ + Mail.php \ + Mail/RFC822.php \ + Mail/sendmail.php \ + Mail/smtp.php \ + Net/Curl.php \ + Net/Dig.php \ + Net/SMTP.php \ + Net/Socket.php \ PEAR.php \ PEAR/Autoloader.php \ PEAR/Command.php \ @@ -41,70 +77,26 @@ PEAR_FILES = \ PEAR/Command/Package.php \ PEAR/Command/Registry.php \ PEAR/Command/Remote.php \ - PEAR/Frontend/CLI.php \ PEAR/Common.php \ PEAR/Config.php \ PEAR/Dependency.php \ + PEAR/Frontend/CLI.php \ PEAR/Installer.php \ PEAR/Packager.php \ PEAR/Registry.php \ PEAR/Remote.php \ + PEAR/Uploader.php \ + Schedule/At.php \ System.php \ XML/Parser.php -# These are moving to /pear (in cvs): -# Crypt/CBC.php \ -# Crypt/HCEMD5.php \ -# DB.php \ -# DB/common.php \ -# DB/fbsql.php \ -# DB/ibase.php \ -# DB/ifx.php \ -# DB/msql.php \ -# DB/mssql.php \ -# DB/mysql.php \ -# DB/oci8.php \ -# DB/odbc.php \ -# DB/pgsql.php \ -# DB/storage.php \ -# DB/sybase.php \ -# Date/Calc.php \ -# Date/Human.php \ -# File/Find.php \ -# File/Passwd.php \ -# File/SearchReplace.php \ -# HTML/Common.php \ -# HTML/Form.php \ -# HTML/IT.php \ -# HTML/ITX.php \ -# HTML/IT_Error.php \ -# HTML/Page.php \ -# HTML/Processor.php \ -# HTML/Select.php \ -# HTML/Table.php \ -# HTTP.php \ -# HTTP/Compress.php \ -# Mail.php \ -# Mail/RFC822.php \ -# Mail/sendmail.php \ -# Mail/smtp.php \ -# Net/Curl.php \ -# Net/Dig.php \ -# Net/SMTP.php \ -# Net/Socket.php \ -# Schedule/At.php \ - -PEAR_PACKAGES=\ - Net_Socket-1.0.tgz - - install-pear: @if $(mkinstalldirs) $(INSTALL_ROOT)$(peardir); then \ for i in $(PEAR_SUBDIRS); do \ $(mkinstalldirs) $(INSTALL_ROOT)$(peardir)/$$i; \ done; \ for dir in PEAR/CommandUI; do \ - test -d $(INSTALL_ROOT)$(peardir)/$$dir && rm -rf $(INSTALL_ROOT)$(peardir)/$$dir; \ + test -d $(INSTALL_ROOT)$(peardir)/$$dir && rmdir $(INSTALL_ROOT)$(peardir)/$$dir; \ done; \ for i in $(PEAR_FILES); do \ echo "Installing $$i"; \ @@ -113,8 +105,6 @@ install-pear: done; \ rm -f $(INSTALL_ROOT)$(peardir)/PEAR/Command/Login.php; \ rm -f $(INSTALL_ROOT)$(peardir)/PEAR/CommandUI/CLI.php; \ - rm -f $(INSTALL_ROOT)$(peardir)/PEAR/CommandResponse.php; \ - rm -f $(INSTALL_ROOT)$(peardir)/PEAR/Uploader.php; \ else \ cat $(srcdir)/install-pear.txt; \ exit 5; \ @@ -158,10 +148,9 @@ HEADER_DIRS = \ ext/standard \ ext/session \ ext/xml \ - ext/xml/expat \ + ext/xml/expat/xmlparse \ + ext/xml/expat/xmltok \ main \ - ext/mbstring \ - ext/pgsql \ regex install-headers: diff --git a/pear/Makefile.in b/pear/Makefile.in index 411335bb5b..f5b01e7bf6 100644 --- a/pear/Makefile.in +++ b/pear/Makefile.in @@ -22,6 +22,8 @@ PEAR_SUBDIRS = \ Mail \ Net \ PEAR \ + PEAR/Command \ + PEAR/Frontend \ Schedule \ XML @@ -69,9 +71,18 @@ PEAR_FILES = \ Net/Socket.php \ PEAR.php \ PEAR/Autoloader.php \ + PEAR/Command.php \ + PEAR/Command/Auth.php \ + PEAR/Command/Common.php \ + PEAR/Command/Config.php \ + PEAR/Command/Install.php \ + PEAR/Command/Package.php \ + PEAR/Command/Registry.php \ + PEAR/Command/Remote.php \ PEAR/Common.php \ PEAR/Config.php \ PEAR/Dependency.php \ + PEAR/Frontend/CLI.php \ PEAR/Installer.php \ PEAR/Packager.php \ PEAR/Registry.php \ @@ -81,17 +92,6 @@ PEAR_FILES = \ System.php \ XML/Parser.php -PEAR_COMMAND_LIBS = \ - pearcmd-common.php \ - pearcmd-help.php \ - pearcmd-info.php \ - pearcmd-install.php \ - pearcmd-list.php \ - pearcmd-package.php \ - pearcmd-remote-list.php \ - pearcmd-show-config.php \ - pearcmd-uninstall.php - install-data-local: @if $(mkinstalldirs) $(INSTALL_ROOT)$(peardir); then \ for i in $(PEAR_SUBDIRS); do \ @@ -125,7 +125,7 @@ BUILD_FILES = \ dynlib.m4 \ acinclude.m4 -bin_SCRIPTS = phpize php-config pear pear-get pearize phptar +bin_SCRIPTS = phpize php-config pear pearize phptar install-build: @echo "Installing build environment" @@ -140,10 +140,6 @@ install-programs: for prog in phpextdist; do \ echo "Installing program: $$prog"; \ $(INSTALL) -m 755 $(srcdir)/scripts/$$prog $(INSTALL_ROOT)$(bindir)/$$prog; \ - done; \ - for lib in $(PEAR_COMMAND_LIBS); do \ - echo "Installing program library: $$lib"; \ - $(INSTALL) -m 644 $(srcdir)/scripts/$$lib $(INSTALL_ROOT)$(bindir)/$$lib; \ done HEADER_DIRS = \ @@ -172,9 +168,6 @@ install-headers: scripts/pear: scripts/pear.in $(top_builddir)/config.status (cd ..;CONFIG_FILES=pear/scripts/pear CONFIG_HEADERS= $(top_builddir)/config.status) -scripts/pear-get: scripts/pear-get.in $(top_builddir)/config.status - (cd ..;CONFIG_FILES=pear/scripts/pear-get CONFIG_HEADERS= $(top_builddir)/config.status) - scripts/phpize: scripts/phpize.in $(top_builddir)/config.status (cd ..;CONFIG_FILES=pear/scripts/phpize CONFIG_HEADERS= $(top_builddir)/config.status) diff --git a/pear/PEAR.php b/pear/PEAR.php index db7f21bfa7..7c5198b6b1 100644 --- a/pear/PEAR.php +++ b/pear/PEAR.php @@ -39,13 +39,8 @@ if (substr(PHP_OS, 0, 3) == 'WIN') { $GLOBALS['_PEAR_default_error_mode'] = PEAR_ERROR_RETURN; $GLOBALS['_PEAR_default_error_options'] = E_USER_NOTICE; -$GLOBALS['_PEAR_default_error_callback'] = ''; $GLOBALS['_PEAR_destructor_object_list'] = array(); -// -// Tests needed: - PEAR inheritance -// - /** * Base class for other PEAR classes. Provides rudimentary * emulation of destructors. @@ -60,8 +55,12 @@ $GLOBALS['_PEAR_destructor_object_list'] = array(); * discarded. If you need to get any debug information from your * destructor, use error_log(), syslog() or something similar. * + * IMPORTANT! To use the emulated destructors you need to create the + * objects by reference, ej: $obj =& new PEAR_child; + * * @since PHP 4.0.2 * @author Stig Bakken + * @see http://pear.php.net/manual/ */ class PEAR { @@ -126,8 +125,8 @@ class PEAR * $_PEAR_destructor_object_list for destructor emulation if a * destructor object exists. * - * @param string (optional) which class to use for error objects, - * defaults to PEAR_Error. + * @param string $error_class (optional) which class to use for error + * objects, defaults to PEAR_Error. * @access public * @return void */ @@ -178,7 +177,7 @@ class PEAR /** * Tell whether a value is a PEAR error. * - * @param mixed the value to test + * @param mixed $data the value to test * @access public * @return bool true if parameter is an error */ @@ -234,11 +233,9 @@ class PEAR if (isset($this)) { $setmode = &$this->_default_error_mode; $setoptions = &$this->_default_error_options; - //$setcallback = &$this->_default_error_callback; } else { $setmode = &$GLOBALS['_PEAR_default_error_mode']; $setoptions = &$GLOBALS['_PEAR_default_error_options']; - //$setcallback = &$GLOBALS['_PEAR_default_error_callback']; } switch ($mode) { @@ -279,12 +276,15 @@ class PEAR * expected errors are in effect until they are popped off the * stack with the popExpect() method. * - * @param mixed a single error code or an array of error codes - * to expect + * Note that this method can not be called statically + * + * @param mixed $code a single error code or an array of error codes + * to expect * * @return int the new depth of the "expected errors" stack + * @access public */ - function expectError($code = "*") + function expectError($code = '*') { if (is_array($code)) { array_push($this->_expected_errors, $code); @@ -371,45 +371,19 @@ class PEAR $mode = PEAR_ERROR_RETURN; } } - + // No mode given, try global ones if ($mode === null) { + // Class error handler if (isset($this) && isset($this->_default_error_mode)) { - $mode = $this->_default_error_mode; - } else { - $mode = $GLOBALS['_PEAR_default_error_mode']; - } - } - - if ($mode == PEAR_ERROR_TRIGGER && $options === null) { - if (isset($this)) { - if (isset($this->_default_error_options)) { - $options = $this->_default_error_options; - } - } else { + $mode = $this->_default_error_mode; + $options = $this->_default_error_options; + // Global error handler + } elseif (isset($GLOBALS['_PEAR_default_error_mode'])) { + $mode = $GLOBALS['_PEAR_default_error_mode']; $options = $GLOBALS['_PEAR_default_error_options']; } } - if ($mode == PEAR_ERROR_CALLBACK) { - if (!is_string($options) && - !(is_array($options) && sizeof($options) == 2 && - is_object($options[0]) && is_string($options[1]))) - { - if (isset($this) && isset($this->_default_error_options)) { - $options = $this->_default_error_options; - } else { - $options = $GLOBALS['_PEAR_default_error_options']; - } - } - } else { - if ($options === null) { - if (isset($this) && isset($this->_default_error_options)) { - $options = $this->_default_error_options; - } else { - $options = $GLOBALS['_PEAR_default_error_options']; - } - } - } if ($error_class !== null) { $ec = $error_class; } elseif (isset($this) && isset($this->_error_class)) { @@ -432,7 +406,7 @@ class PEAR * you can easily override the actual error handler for some code and restore * it later with popErrorHandling. * - * @param $mode mixed (same as setErrorHandling) + * @param $mode mixed (same as setErrorHandling) * @param $options mixed (same as setErrorHandling) * * @return bool Always true @@ -446,13 +420,9 @@ class PEAR if (isset($this)) { $def_mode = &$this->_default_error_mode; $def_options = &$this->_default_error_options; - // XXX Used anywhere? - //$def_callback = &$this->_default_error_callback; } else { $def_mode = &$GLOBALS['_PEAR_default_error_mode']; $def_options = &$GLOBALS['_PEAR_default_error_options']; - // XXX Used anywhere? - //$def_callback = &$GLOBALS['_PEAR_default_error_callback']; } $stack = array(); $stack[] = array($def_mode, $def_options); @@ -652,7 +622,7 @@ class PEAR_Error * @return string full error message * @access public */ - function getMessage () + function getMessage() { return ($this->error_message_prefix . $this->message); } @@ -681,7 +651,7 @@ class PEAR_Error * @return string error/exception name (type) * @access public */ - function getType () + function getType() { return get_class($this); } @@ -695,7 +665,7 @@ class PEAR_Error * @return string user-supplied information * @access public */ - function getUserInfo () + function getUserInfo() { return $this->userinfo; } @@ -709,7 +679,7 @@ class PEAR_Error * @return string debug information * @access public */ - function getDebugInfo () + function getDebugInfo() { return $this->getUserInfo(); } diff --git a/pear/PEAR/Command.php b/pear/PEAR/Command.php index 49807d0339..851099e66b 100644 --- a/pear/PEAR/Command.php +++ b/pear/PEAR/Command.php @@ -27,6 +27,18 @@ require_once "PEAR.php"; */ $GLOBALS['_PEAR_Command_commandlist'] = array(); +/** + * Which user interface class is being used. + * @var string class name + */ +$GLOBALS['_PEAR_Command_uiclass'] = 'PEAR_Frontend_CLI'; + +/** +* The options accepted by the commands +* @var string the options +*/ +$GLOBALS['_PEAR_Command_commandopts'] = ''; + /** * PEAR command class, a simple factory class for administrative * commands. @@ -82,17 +94,40 @@ class PEAR_Command * * @access public */ - function factory(&$config, $command) + function factory($command, &$config) { if (empty($GLOBALS['_PEAR_Command_commandlist'])) { PEAR_Command::registerCommands(); } if (isset($GLOBALS['_PEAR_Command_commandlist'][$command])) { $class = $GLOBALS['_PEAR_Command_commandlist'][$command]; - $obj =& new $class($config); + $obj = &new $class(PEAR_Command::getFrontendObject(), $config); return $obj; } - return PEAR::raiseError("unknown command: $command"); + return PEAR::raiseError("unknown command `$command'"); + } + + function &getFrontendObject() + { + global $_PEAR_Command_uiclass, $_PEAR_Command_uiobject; + if (empty($_PEAR_Command_uiobject)) { + $_PEAR_Command_uiobject = &new $_PEAR_Command_uiclass; + } + return $_PEAR_Command_uiobject; + } + + function setFrontendClass($uiclass) + { + $GLOBALS['_PEAR_Command_uiclass'] = $uiclass; + $file = str_replace("_", "/", $uiclass) . '.php'; + include_once $file; + return class_exists(strtolower($uiclass)); + } + + function setFrontendType($uitype) + { + $uiclass = 'PEAR_Frontend_' . $uitype; + return PEAR_Command::setFrontendClass($uiclass); } /** @@ -119,23 +154,31 @@ class PEAR_Command } $dp = @opendir($dir); if (empty($dp)) { - return PEAR::raiseError("PEAR_Command::registerCommands: opendir($dir) failed"); + return PEAR::raiseError("PEAR_Command::registerCommands: ". + "opendir($dir) failed"); } if (!$merge) { $GLOBALS['_PEAR_Command_commandlist'] = array(); } + $cmdopts = array(); while ($entry = readdir($dp)) { - if ($entry{0} == '.' || substr($entry, -4) != '.php' || $entry == 'Common.php') { + if ($entry{0} == '.' || substr($entry, -4) != '.php' || + $entry == 'Common.php') + { continue; } $class = "PEAR_Command_".substr($entry, 0, -4); $file = "$dir/$entry"; include_once $file; + // List of commands $implements = call_user_func(array($class, "getCommands")); foreach ($implements as $command) { $GLOBALS['_PEAR_Command_commandlist'][$command] = $class; } + // List of options accepted + $cmdopts = array_merge($cmdopts, call_user_func(array($class, "getOptions"))); } + $GLOBALS['_PEAR_Command_commandopts'] = implode('', $cmdopts); return true; } @@ -149,8 +192,19 @@ class PEAR_Command */ function getCommands() { + if (empty($GLOBALS['_PEAR_Command_commandlist'])) { + PEAR_Command::registerCommands(); + } return $GLOBALS['_PEAR_Command_commandlist']; } + + function getOptions() + { + if (empty($GLOBALS['_PEAR_Command_commandlist'])) { + PEAR_Command::registerCommands(); + } + return $GLOBALS['_PEAR_Command_commandopts']; + } } ?> \ No newline at end of file diff --git a/pear/PEAR/Command/Auth.php b/pear/PEAR/Command/Auth.php index f59f730b83..81c393e8d6 100644 --- a/pear/PEAR/Command/Auth.php +++ b/pear/PEAR/Command/Auth.php @@ -55,16 +55,6 @@ class PEAR_Command_Auth extends PEAR_Command_Common } // }}} - - function getHelp($command) - { - switch ($command) { - case 'login': - return array(null, 'Connects to the remote server'); - case 'logout': - return array(null, 'Disconnects from the remote server'); - } - } // {{{ run() /** @@ -83,27 +73,28 @@ class PEAR_Command_Auth extends PEAR_Command_Common */ function run($command, $options, $params) { + $cf = $this->config; $failmsg = ''; - $server = $this->config->get('master_server'); + $server = $cf->get('master_server'); switch ($command) { case 'login': { - $remote = new PEAR_Remote($this->config); - $username = $this->config->get('username'); + $remote = new PEAR_Remote($cf); + $username = $cf->get('username'); if (empty($username)) { $username = @$_ENV['USER']; } $this->ui->displayLine("Logging in to $server."); $username = trim($this->ui->userDialog('Username', 'text', $username)); - $this->config->set('username', $username); + $cf->set('username', $username); $password = trim($this->ui->userDialog('Password', 'password')); - $this->config->set('password', $password); + $cf->set('password', $password); $remote->expectError(401); $ok = $remote->call('logintest'); $remote->popExpect(); if ($ok === true) { $this->ui->displayLine("Logged in."); - $this->config->store(); + $cf->store(); } else { $this->ui->displayLine("Login failed!"); } @@ -111,9 +102,9 @@ class PEAR_Command_Auth extends PEAR_Command_Common } case 'logout': { $this->ui->displayLine("Logging out from $server."); - $this->config->remove('username'); - $this->config->remove('password'); - $this->config->store(); + $cf->remove('username'); + $cf->remove('password'); + $cf->store(); break; } default: { diff --git a/pear/PEAR/Command/Common.php b/pear/PEAR/Command/Common.php index e54c1694f1..7ea724a999 100644 --- a/pear/PEAR/Command/Common.php +++ b/pear/PEAR/Command/Common.php @@ -19,7 +19,7 @@ // $Id$ require_once "PEAR.php"; -require_once "PEAR/CommandResponse.php"; +//require_once "PEAR/CommandResponse.php"; class PEAR_Command_Common extends PEAR { @@ -31,15 +31,27 @@ class PEAR_Command_Common extends PEAR */ var $config; + /** + * User Interface object, for all interaction with the user. + * @var object + */ + var $ui; + /** * PEAR_Command_Common constructor. * * @access public */ - function PEAR_Command_Common() + function PEAR_Command_Common(&$ui, &$config) { parent::PEAR(); - $this->config = PEAR_Config::singleton(); + $this->config = &$config; + $this->ui = &$ui; + } + + function getOptions() + { + return array(); } /** @@ -56,13 +68,13 @@ class PEAR_Command_Common extends PEAR * * @see PEAR_CommandResponse */ +/* function &makeResponse($status, $message, $encoding = null) { - $obj =& new PEAR_CommandResponse($status, $message, $encoding); + $obj = &new PEAR_CommandResponse($status, $message, $encoding); return $obj; } - - +*/ } ?> \ No newline at end of file diff --git a/pear/PEAR/Command/Config.php b/pear/PEAR/Command/Config.php index 009c2d243e..1fdcf32747 100644 --- a/pear/PEAR/Command/Config.php +++ b/pear/PEAR/Command/Config.php @@ -14,8 +14,6 @@ // | license@php.net so we can mail you a copy immediately. | // +----------------------------------------------------------------------+ // | Author: Stig Bakken | -// | Tomas V.V.Cox | -// | | // +----------------------------------------------------------------------+ // // $Id$ @@ -59,66 +57,44 @@ class PEAR_Command_Config extends PEAR_Command_Common } // }}} - - function getHelp($command) - { - switch ($command) { - case 'config-show': - $ret = array('[]', 'Displays the configuration'); - break; - case 'config-get': - $ret = array(' []', - 'Displays the value of the given parameter'); - break; - case 'config-set': - $ret = array(' []', - 'Sets the value of a parameter in the config'); - break; - } - $ret[1] .= "\n". - " Where to store/get the configuration. The installer\n". - " supports 'user' (per user conf) and 'system' (global conf)"; - return $ret; - } // {{{ run() function run($command, $options, $params) { - $cf = &$this->config; + $cf =& $this->config; $failmsg = ''; + $params[0] = (isset($params[0])) ? $params[0] : null; + $params[1] = (isset($params[1])) ? $params[1] : null; switch ($command) { case 'config-show': { - // $params[0] -> the layer - if ($error = $this->_checkLayer(@$params[0])) { - $failmsg .= $error; - break; - } $keys = $cf->getKeys(); sort($keys); $this->ui->startTable(array('caption' => 'Configuration:')); - foreach ($keys as $key) { - $type = $cf->getType($key); - $value = $cf->get($key, @$params[0]); - if ($type == 'password' && $value) { - $value = '********'; + if (isset($params[0]) && $cf->isDefined($params[0])) { + foreach ($keys as $key) { + $type = $cf->getType($key); + $value = $cf->get($key, $params[0]); + if ($type == 'password' && $value) { + $value = '********'; + } + $this->ui->tableRow(array($key, $value)); } - if (empty($value)) { - $value = ''; + } else { + foreach ($keys as $key) { + $type = $cf->getType($key); + $value = $cf->get($key, $params[0]); + if ($type == 'password' && $value) { + $value = '********'; + } + $this->ui->tableRow(array($key, $value)); } - $this->ui->tableRow(array($key, $value)); } $this->ui->endTable(); break; } case 'config-get': { - // $params[0] -> the parameter - // $params[1] -> the layer - if ($error = $this->_checkLayer(@$params[1])) { - $failmsg .= $error; - break; - } if (sizeof($params) < 1 || sizeof($params) > 2) { - $failmsg .= "config-get expects 1 or 2 parameters. Try \"help config-get\" for help"; + $failmsg .= "config-get expects 1 or 2 parameters"; } elseif (sizeof($params) == 1) { $this->ui->displayLine("$params[0] = " . $cf->get($params[0])); } else { @@ -128,22 +104,15 @@ class PEAR_Command_Config extends PEAR_Command_Common break; } case 'config-set': { - // $param[0] -> a parameter to set - // $param[1] -> the value for the parameter - // $param[2] -> the layer if (sizeof($params) < 2 || sizeof($params) > 3) { - $failmsg .= "config-set expects 2 or 3 parameters. Try \"help config-set\" for help"; - break; - } - if ($error = $this->_checkLayer(@$params[2])) { - $failmsg .= $error; + $failmsg .= "config-set expects 2 or 3 parameters"; break; - } - if (!call_user_func_array(array(&$cf, 'set'), $params)) - { - $failmsg = "config-set (" . implode(", ", $params) . ") failed"; } else { - $cf->store(); + if (!call_user_func_array(array($cf, 'set'), $params)) + { + $failmsg = "config-set (" . + implode(", ", $params) . ") failed"; + } } break; } @@ -158,24 +127,6 @@ class PEAR_Command_Config extends PEAR_Command_Common } // }}} - - /** - * Checks if a layer is defined or not - * - * @param string $layer The layer to search for - * @return mixed False on no error or the error message - */ - function _checkLayer($layer = null) - { - if (!empty($layer)) { - $layers = $this->config->getLayers(); - if (!in_array($layer, $layers)) { - return " only the layers: \"" . implode('" or "', $layers) . "\" are supported"; - } - } - return false; - } - } ?> \ No newline at end of file diff --git a/pear/PEAR/Command/Install.php b/pear/PEAR/Command/Install.php index 0d99f85b1a..7204c309bf 100644 --- a/pear/PEAR/Command/Install.php +++ b/pear/PEAR/Command/Install.php @@ -28,26 +28,25 @@ require_once "PEAR/Installer.php"; */ class PEAR_Command_Install extends PEAR_Command_Common { - /** Stack of executing commands, to make run() re-entrant - * @var array - */ - var $command_stack; // XXX UNUSED to make run() re-entrant + // {{{ properties + // }}} - /** Currently executing command. - * @var string - */ - var $command; // XXX UNUSED + // {{{ constructor /** * PEAR_Command_Install constructor. * * @access public */ - function PEAR_Command_Install() + function PEAR_Command_Install(&$ui, &$config) { - parent::PEAR_Command_Common(); + parent::PEAR_Command_Common($ui, $config); } + // }}} + + // {{{ getCommands() + /** * Return a list of all the commands defined by this class. * @return array list of commands @@ -58,41 +57,57 @@ class PEAR_Command_Install extends PEAR_Command_Common return array('install', 'uninstall', 'upgrade'); } + // }}} + // {{{ run() + function run($command, $options, $params) { - $installer =& new PEAR_Installer($options['php_dir'], - $options['ext_dir'], - $options['doc_dir']); - $installer->debug = @$options['verbose']; - $status = PEAR_COMMAND_SUCCESS; - ob_start(); + $installer = &new PEAR_Installer($this->config->get('php_dir'), + $this->config->get('ext_dir'), + $this->config->get('doc_dir')); + $installer->debug = $this->config->get('verbose'); + + $failmsg = ''; + $opts = array(); switch ($command) { - case 'install': - case 'upgrade': { - if ($command == 'upgrade') { - $options['upgrade'] = true; + case 'upgrade': + $opts['upgrade'] = true; + // fall through + case 'install': { + if (isset($options['f'])) { + $opts['force'] = true; } - if ($installer->install($params[0], $options, $this->config)) { - print "install ok\n"; + // XXX The ['nodeps'] option is still missing + if ($installer->install(@$params[0], $opts, $this->config)) { + $this->ui->displayLine("install ok"); } else { - print "install failed\n"; - $status = PEAR_COMMAND_FAILURE; + $failmsg = "install failed"; } break; } case 'uninstall': { - if ($installer->uninstall($params[0], $uninstall_options)) { - print "uninstall ok\n"; + if ($installer->uninstall($params[0], $options)) { + $this->ui->displayLine("uninstall ok"); } else { - print "uninstall failed\n"; - $status = PEAR_COMMAND_FAILURE; + $failmsg = "uninstall failed"; } break; - } + } + default: { + return false; + } + } + if ($failmsg) { + return $this->raiseError($failmsg); } - $output = ob_get_contents(); - ob_end_clean(); - return $this->makeResponse($status, $output); + return true; + } + + // }}} + + function getOptions() + { + return array('f'); } } diff --git a/pear/PEAR/Command/Package.php b/pear/PEAR/Command/Package.php index eb2d9771b2..a95f45a1fd 100644 --- a/pear/PEAR/Command/Package.php +++ b/pear/PEAR/Command/Package.php @@ -1,22 +1,4 @@ | -// +----------------------------------------------------------------------+ -// -// $Id$ require_once 'PEAR/Command/Common.php'; require_once 'PEAR/Packager.php'; @@ -38,26 +20,6 @@ class PEAR_Command_Package extends PEAR_Command_Common // }}} - // {{{ _displayValidationResults() - - function _displayValidationResults($err, $warn, $strict = false) - { - foreach ($err as $e) { - $this->ui->displayLine("Error: $e"); - } - foreach ($warn as $w) { - $this->ui->displayLine("Warning: $w"); - } - $this->ui->displayLine(sprintf('Validation: %d error(s), %d warning(s)', - sizeof($err), sizeof($warn))); - if ($strict && sizeof($err) > 0) { - $this->ui->displayLine("Fix these errors and try again."); - return false; - } - return true; - } - - // }}} // {{{ getCommands() /** @@ -68,43 +30,8 @@ class PEAR_Command_Package extends PEAR_Command_Common function getCommands() { return array('package', - 'package-info', 'package-list', - 'package-validate', - 'cvstag'); - } - - // }}} - // {{{ getOptions() - - function getOptions() - { - return array('Z', 'n' /*, 'f', 'd', 'q', 'Q'*/); - } - - // }}} - // {{{ getHelp() - - function getHelp($command) - { - switch ($command) { - case 'package': - return array('[]', - 'Creates a PEAR package from its description file (usually '. - 'named as package.xml)'); - case 'package-list': - return array('', - 'List the contents of a PEAR package'); - case 'packge-info': - return array('', - 'Shows information about a PEAR package'); - case 'package-validate': - return array('', - 'Verifies a package or description file'); - case 'cvstag': - return array('', - 'Runs "cvs tag" on files contained in a release'); - } + 'package-info'); } // }}} @@ -131,19 +58,13 @@ class PEAR_Command_Package extends PEAR_Command_Common // {{{ package case 'package': { - $pkginfofile = isset($params[0]) ? $params[0] : 'package.xml'; + $pkginfofile = isset($params[0]) ? $params[0] : null; ob_start(); $packager =& new PEAR_Packager($this->config->get('php_dir'), $this->config->get('ext_dir'), $this->config->get('doc_dir')); $packager->debug = $this->config->get('verbose'); - $err = $warn = array(); - $packager->validatePackageInfo($pkginfofile, $err, $warn); - if (!$this->_displayValidationResults($err, $warn, true)) { - break; - } - $compress = empty($options['Z']) ? true : false; - $result = $packager->Package($pkginfofile, $compress); + $result = $packager->Package($pkginfofile); $output = ob_get_contents(); ob_end_clean(); $lines = explode("\n", $output); @@ -151,7 +72,9 @@ class PEAR_Command_Package extends PEAR_Command_Common $this->ui->displayLine($line); } if (PEAR::isError($result)) { - $this->ui->displayLine("Package failed: ".$result->getMessage()); + $this->ui->displayLine("Package failed!"); + } else { + $this->ui->displayLine("Package ok."); } break; } @@ -160,14 +83,7 @@ class PEAR_Command_Package extends PEAR_Command_Common // {{{ package-list case 'package-list': { - // $params[0] -> the PEAR package to list its contents - if (sizeof($params) != 1) { - $failmsg = "Command package-list requires a valid PEAR package filename ". - " as the first argument. Try the command \"help package-list\""; - break; - } $obj = new PEAR_Common(); - if (PEAR::isError($info = $obj->infoFromTgzFile($params[0]))) { return $info; } @@ -180,9 +96,9 @@ class PEAR_Command_Package extends PEAR_Command_Common foreach ($list as $file => $att) { if (isset($att['baseinstalldir'])) { $dest = $att['baseinstalldir'] . DIRECTORY_SEPARATOR . - $file; + basename($file); } else { - $dest = $file; + $dest = basename($file); } switch ($att['role']) { case 'test': @@ -288,89 +204,6 @@ class PEAR_Command_Package extends PEAR_Command_Common break; } - // }}} - // {{{ package-validate - - case 'package-validate': { - if (sizeof($params) < 1) { - $params[0] = "package.xml"; - } - $obj = new PEAR_Common; - $info = null; - if (file_exists($params[0])) { - $fp = fopen($params[0], "r"); - $test = fread($fp, 5); - fclose($fp); - if ($test == "infoFromDescriptionFile($params[0]); - } - } - if (empty($info)) { - $info = $obj->infoFromTgzFile($params[0]); - } - if (PEAR::isError($info)) { - return $this->raiseError($info); - } - $obj->validatePackageInfo($info, $err, $warn); - $this->_displayValidationResults($err, $warn); - break; - } - - // }}} - // {{{ cvstag - - case 'cvstag': { - if (sizeof($params) < 1) { - $help = $this->getHelp($command); - return $this->raiseError("$command: missing parameter: $help[0]"); - } - $obj = new PEAR_Common; - $info = $obj->infoFromDescriptionFile($params[0]); - if (PEAR::isError($info)) { - return $this->raiseError($info); - } - $err = $warn = array(); - $obj->validatePackageInfo($info, $err, $warn); - if (!$this->_displayValidationResults($err, $warn, true)) { - break; - } - $version = $info['version']; - $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $version); - $cvstag = "RELEASE_$cvsversion"; - $files = array_keys($info['filelist']); - $command = "cvs"; - /* until the getopt bug is fixed, these won't work: - if (isset($options['q'])) { - $command .= ' -q'; - } - if (isset($options['Q'])) { - $command .= ' -Q'; - } - */ - $command .= ' tag'; - if (isset($options['f'])) { - $command .= ' -f'; - } - /* neither will this one: - if (isset($options['d'])) { - $command .= ' -d'; - } - */ - $command .= ' ' . $cvstag . ' ' . escapeshellarg($params[0]); - foreach ($files as $file) { - $command .= ' ' . escapeshellarg($file); - } - $this->ui->displayLine("+ $command"); - if (empty($options['n'])) { - $fp = popen($command, "r"); - while ($line = fgets($fp, 1024)) { - $this->ui->displayLine(rtrim($line)); - } - pclose($fp); - } - break; - } - // }}} default: { return false; @@ -384,6 +217,7 @@ class PEAR_Command_Package extends PEAR_Command_Common // }}} + } ?> \ No newline at end of file diff --git a/pear/PEAR/Command/Registry.php b/pear/PEAR/Command/Registry.php index 92777094ca..25e0c576b4 100644 --- a/pear/PEAR/Command/Registry.php +++ b/pear/PEAR/Command/Registry.php @@ -29,15 +29,7 @@ class PEAR_Command_Registry extends PEAR_Command_Common */ function getCommands() { - return array('list-installed', 'shell-test'); - } - - function getHelp($command) - { - switch ($command) { - case 'list-installed': - return array(null, 'List the installed PEAR packages in the system'); - } + return array('list-installed'); } // }}} @@ -62,8 +54,6 @@ class PEAR_Command_Registry extends PEAR_Command_Common $failmsg = ''; $cf = &PEAR_Config::singleton(); switch ($command) { - // {{{ list-installed - case 'list-installed': { $reg = new PEAR_Registry($cf->get('php_dir')); $installed = $reg->packageInfo(); @@ -73,47 +63,16 @@ class PEAR_Command_Registry extends PEAR_Command_Common 'border' => true)); foreach ($installed as $package) { if ($i++ % 20 == 0) { - $this->ui->tableRow( - array('Package', 'Version', 'State'), - array('bold' => true)); + $this->ui->tableRow(array('Package', 'Version', 'State'), + array('bold' => true)); } $this->ui->tableRow(array($package['package'], $package['version'], - @$package['release_state'])); + $package['release_state'])); } $this->ui->endTable(); break; } - - // }}} - case 'shell-test': { - // silence error messages for the rest of the execution - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $reg = &new PEAR_Registry($this->config->get('php_dir')); - // "pear shell-test Foo" - if (sizeof($params) == 1) { - if (!$reg->packageExists($params[0])) { - exit(1); - } - // "pear shell-test Foo 1.0" - } elseif (sizeof($params) == 2) { - $v = $reg->packageInfo($params[0], 'version'); - if (!$v || !version_compare($v, $params[1], "ge")) { - exit(1); - } - // "pear shell-test Foo ge 1.0" - } elseif (sizeof($params) == 3) { - $v = $reg->packageInfo($params[0], 'version'); - if (!$v || !version_compare($v, $params[2], $params[1])) { - exit(1); - } - } else { - PEAR::popErrorHandling(); - PEAR::raiseError("$command: expects 1 to 3 parameters"); - exit(1); - } - break; - } default: { return false; } diff --git a/pear/PEAR/Common.php b/pear/PEAR/Common.php index 929a97917e..efbaaac2a7 100644 --- a/pear/PEAR/Common.php +++ b/pear/PEAR/Common.php @@ -24,11 +24,22 @@ require_once 'Archive/Tar.php'; require_once 'System.php'; /** + * List of temporary files and directories registered by + * PEAR_Common::addTempFile(). + * @var array + */ +$GLOBALS['_PEAR_Common_tempfiles'] = array(); + +/* * TODO: * - check in inforFromDescFile that the minimal data needed is present * (pack name, version, files, others?) * - inherance of dir attribs to files may fail under certain circumstances */ + +/** + * Class providing common functionality for PEAR adminsitration classes. + */ class PEAR_Common extends PEAR { // {{{ properties @@ -42,9 +53,6 @@ class PEAR_Common extends PEAR /** array of attributes of the currently parsed XML element */ var $current_attributes = array(); - /** list of temporary files created by this object */ - var $_tempfiles = array(); - /** assoc with information about a package */ var $pkginfo = array(); @@ -58,30 +66,36 @@ class PEAR_Common extends PEAR * Permitted release states * @var array */ - var $releases_states = array('alpha','beta','stable','snapshot'); + var $releases_states = array('alpha','beta','stable','snapshot','devel'); // }}} // {{{ constructor + /** + * PEAR_Common constructor + * + * @access public + */ function PEAR_Common() { - $GLOBALS['_PEAR_Common_tempfiles'] = array(); - $this->_tempfiles =& $GLOBALS['_PEAR_Common_tempfiles']; $this->PEAR(); } // }}} // {{{ destructor + /** + * PEAR_Common destructor + * + * @access private + */ function _PEAR_Common() { // doesn't work due to bug #14744 //$tempfiles = $this->_tempfiles; $tempfiles =& $GLOBALS['_PEAR_Common_tempfiles']; - while (is_array($tempfiles) && - $file = array_shift($tempfiles)) - { + while ($file = array_shift($tempfiles)) { if (@is_dir($file)) { System::rm("-rf $file"); } elseif (file_exists($file)) { @@ -93,14 +107,35 @@ class PEAR_Common extends PEAR // }}} // {{{ addTempFile() + /** + * Register a temporary file or directory. When the destructor is + * executed, all registered temporary files and directories are + * removed. + * + * @param string name of file or directory + * + * @return void + * + * @access public + */ function addTempFile($file) { - $this->_tempfiles[] = $file; + $GLOBALS['_PEAR_Common_tempfiles'][] = $file; } // }}} // {{{ mkDirHier() + /** + * Wrapper to System::mkDir(), creates a directory as well as + * any necessary parent directories. + * + * @param string directory name + * + * @return bool TRUE on success, or a PEAR error + * + * @access public + */ function mkDirHier($dir) { $this->log(2, "+ create dir $dir"); @@ -110,6 +145,17 @@ class PEAR_Common extends PEAR // }}} // {{{ log() + /** + * Logging method. + * + * @param int log level (0 is quiet, higher is noisier) + * + * @param string message to write to the log + * + * @return void + * + * @access public + */ function log($level, $msg) { if ($this->debug >= $level) { @@ -120,9 +166,25 @@ class PEAR_Common extends PEAR // }}} // {{{ mkTempDir() - function mkTempDir() + /** + * Create and register a temporary directory. + * + * @param string (optional) Directory to use as tmpdir. Will use + * system defaults (for example /tmp or c:\windows\temp) if not + * specified + * + * @return string name of created directory + * + * @access public + */ + function mkTempDir($tmpdir = '') { - if (!$tmpdir = System::mktemp('-d pear')) { + if ($tmpdir) { + $topt = "-t $tmpdir "; + } else { + $topt = ''; + } + if (!$tmpdir = System::mktemp($topt . '-d pear')) { return false; } $this->addTempFile($tmpdir); @@ -132,7 +194,77 @@ class PEAR_Common extends PEAR // }}} // {{{ _element_start() + /** + * XML parser callback for starting elements. Used while package + * format version is not yet known. + * + * @param resource XML parser resource + * @param string name of starting element + * @param array element attributes, name => value + * + * @return void + * + * @access private + */ function _element_start($xp, $name, $attribs) + { + array_push($this->element_stack, $name); + $this->current_element = $name; + $spos = sizeof($this->element_stack) - 2; + $this->prev_element = ($spos >= 0) ? $this->element_stack[$spos] : ''; + $this->current_attributes = $attribs; + switch ($name) { + case 'package': { + if (isset($attribs['version'])) { + $vs = preg_replace('/[^0-9a-z]/', '_', $attribs['version']); + } else { + $vs = '1_0'; + } + $elem_start = '_element_start_'. $vs; + $elem_end = '_element_end_'. $vs; + $cdata = '_pkginfo_cdata_'. $vs; + xml_set_element_handler($xp, $elem_start, $elem_end); + xml_set_character_data_handler($xp, $cdata); + break; + } + } + } + + // }}} + // {{{ _element_end() + + /** + * XML parser callback for ending elements. Used while package + * format version is not yet known. + * + * @param resource XML parser resource + * @param string name of ending element + * + * @return void + * + * @access private + */ + function _element_end($xp, $name) + { + } + + // }}} + + // Support for package DTD v1.0: + // {{{ _element_start_1_0() + + /** + * XML parser callback for ending elements. Used for version 1.0 + * packages. + * + * @param resource XML parser resource + * @param string name of ending element + * + * @return void + * + * @access private + */ + function _element_start_1_0($xp, $name, $attribs) { array_push($this->element_stack, $name); $this->current_element = $name; @@ -142,11 +274,8 @@ class PEAR_Common extends PEAR $this->cdata = ''; switch ($name) { case 'dir': - if (isset($this->dir_names)) { + if ($attribs['name'] != '/') { $this->dir_names[] = $attribs['name']; - } else { - // Don't add the root dir - $this->dir_names = array(); } if (isset($attribs['baseinstalldir'])) { $this->dir_install = $attribs['baseinstalldir']; @@ -157,7 +286,7 @@ class PEAR_Common extends PEAR break; case 'libfile': $this->lib_atts = $attribs; - $this->lib_atts['role'] = 'extension'; + $this->lib_atts['role'] = 'extsrc'; break; case 'maintainers': $this->pkginfo['maintainers'] = array(); @@ -184,20 +313,35 @@ class PEAR_Common extends PEAR } break; case 'deps': - $this->pkginfo['release_deps'] = array(); + if (!$this->in_changelog) { + $this->pkginfo['release_deps'] = array(); + } break; case 'dep': // dependencies array index - $this->d_i = (isset($this->d_i)) ? $this->d_i + 1 : 0; - $this->pkginfo['release_deps'][$this->d_i] = $attribs; + if (!$this->in_changelog) { + $this->d_i = (isset($this->d_i)) ? $this->d_i + 1 : 0; + $this->pkginfo['release_deps'][$this->d_i] = $attribs; + } break; } } // }}} - // {{{ _element_end() + // {{{ _element_end_1_0() - function _element_end($xp, $name) + /** + * XML parser callback for ending elements. Used for version 1.0 + * packages. + * + * @param resource XML parser resource + * @param string name of ending element + * + * @return void + * + * @access private + */ + function _element_end_1_0($xp, $name) { $data = trim($this->cdata); switch ($name) { @@ -278,7 +422,7 @@ class PEAR_Common extends PEAR case 'file': $this->current_file = $data; $path = ''; - if (!empty($this->dir_names)) { + if (count($this->dir_names)) { foreach ($this->dir_names as $dir) { $path .= $dir . DIRECTORY_SEPARATOR; } @@ -297,7 +441,6 @@ class PEAR_Common extends PEAR } break; case 'libfile': - $this->lib_name = $data; $path = ''; if (!empty($this->dir_names)) { foreach ($this->dir_names as $dir) { @@ -313,12 +456,19 @@ class PEAR_Common extends PEAR $this->filelist[$path]['baseinstalldir'] = $this->dir_install; } if (isset($this->lib_sources)) { - $this->filelist[$path]['sources'] = $this->lib_sources; + $this->filelist[$path]['sources'] = implode(' ', $this->lib_sources); } unset($this->lib_atts); unset($this->lib_sources); + unset($this->lib_name); + break; + case 'libname': + $this->lib_name = $data; break; case 'maintainer': + if (empty($this->pkginfo['maintainers'][$this->m_i]['role'])) { + $this->pkginfo['maintainers'][$this->m_i]['role'] = 'lead'; + } $this->m_i++; break; case 'release': @@ -339,22 +489,109 @@ class PEAR_Common extends PEAR } // }}} - // {{{ _pkginfo_cdata() + // {{{ _pkginfo_cdata_1_0() - function _pkginfo_cdata($xp, $data) + /** + * XML parser callback for character data. Used for version 1.0 + * packages. + * + * @param resource XML parser resource + * @param string character data + * + * @return void + * + * @access private + */ + function _pkginfo_cdata_1_0($xp, $data) { $this->cdata .= $data; } + // }}} + + // {{{ infoFromTgzFile() + + /** + * Returns information about a package file. Expects the name of + * a gzipped tar file as input. + * + * @param string name of .tgz file + * + * @return array array with package information + * + * @access public + * + */ + function infoFromTgzFile($file) + { + if (!@is_file($file)) { + return $this->raiseError('tgz :: could not open file'); + } + $tar = new Archive_Tar($file, true); + $content = $tar->listContent(); + if (!is_array($content)) { + return $this->raiseError('tgz :: could not get contents of package'); + } + $xml = null; + foreach ($content as $file) { + $name = $file['filename']; + if ($name == 'package.xml') { + $xml = $name; + } elseif (ereg('^.*/package.xml$', $name, $match)) { + $xml = $match[0]; + } + } + $tmpdir = System::mkTemp('-d pear'); + $this->addTempFile($tmpdir); + if (!$xml || !$tar->extractList($xml, $tmpdir)) { + return $this->raiseError('tgz :: could not extract the package.xml file'); + } + return $this->infoFromDescriptionFile("$tmpdir/$xml"); + } + // }}} // {{{ infoFromDescriptionFile() + /** + * Returns information about a package file. Expects the name of + * a package xml file as input. + * + * @param string name of package xml file + * + * @return array array with package information + * + * @access public + * + */ function infoFromDescriptionFile($descfile) { if (!@is_file($descfile) || !is_readable($descfile) || (!$fp = @fopen($descfile, 'r'))) { return $this->raiseError("Unable to open $descfile"); } + + // read the whole thing so we only get one cdata callback + // for each block of cdata + $data = fread($fp, filesize($descfile)); + return $this->infoFromString($data); + } + + // }}} + // {{{ infoFromString() + + /** + * Returns information about a package file. Expects the contents + * of a package xml file as input. + * + * @param string name of package xml file + * + * @return array array with package information + * + * @access public + * + */ + function infoFromString($data) + { $xp = @xml_parser_create(); if (!$xp) { return $this->raiseError('Unable to create XML parser'); @@ -370,17 +607,16 @@ class PEAR_Common extends PEAR $this->destdir = ''; $this->pkginfo['filelist'] = array(); $this->filelist =& $this->pkginfo['filelist']; + $this->dir_names = array(); $this->in_changelog = false; - // read the whole thing so we only get one cdata callback - // for each block of cdata - $data = fread($fp, filesize($descfile)); if (!xml_parse($xp, $data, 1)) { + $code = xml_get_error_code($xp); $msg = sprintf("XML error: %s at line %d", - xml_error_string(xml_get_error_code($xp)), + xml_error_string($code), xml_get_current_line_number($xp)); xml_parser_free($xp); - return $this->raiseError($msg); + return $this->raiseError($msg, $code); } xml_parser_free($xp); @@ -393,36 +629,128 @@ class PEAR_Common extends PEAR return $this->pkginfo; } // }}} - // {{{ infoFromTgzFile() + // {{{ xmlFromInfo() /** - * Returns info from a tgz pear package - */ - function infoFromTgzFile($file) + * Return an XML document based on the package info (as returned + * by the PEAR_Common::infoFrom* methods). + * + * @param array package info + * + * @return string XML data + * + * @access public + */ + function xmlFromInfo($pkginfo) { - if (!@is_file($file)) { - return $this->raiseError('tgz :: could not open file'); + static $maint_map = array( + "handle" => "user", + "name" => "name", + "email" => "email", + "role" => "role", + ); + $ret = "\n"; + //$ret .= "\n"; + $ret .= " + $pkginfo[package] + ".htmlspecialchars($pkginfo['summary'])." + ".htmlspecialchars($pkginfo['description'])." + +"; + foreach ($pkginfo['maintainers'] as $maint) { + $ret .= " \n"; + foreach ($maint_map as $idx => $elm) { + $ret .= " <$elm>"; + $ret .= htmlspecialchars($maint[$idx]); + $ret .= "\n"; + } + $ret .= " \n"; } - $tar = new Archive_Tar($file, true); - $content = $tar->listContent(); - if (!is_array($content)) { - return $this->raiseError('tgz :: could not get contents of package'); + $ret .= " \n"; + $ret .= $this->_makeReleaseXml($pkginfo); + if (@sizeof($pkginfo['changelog']) > 0) { + $ret .= " \n"; + foreach ($pkginfo['changelog'] as $oldrelease) { + $ret .= $this->_makeReleaseXml($oldrelease, true); + } + $ret .= " \n"; } - $xml = null; - foreach ($content as $file) { - $name = $file['filename']; - if (ereg('^.*/package.xml$', $name, $match)) { - $xml = $match[0]; + $ret .= "\n"; + return $ret; + } + + // }}} + // {{{ _makeReleaseXml() + + /** + * Generate part of an XML description with release information. + * + * @param array array with release information + * @param bool whether the result will be in a changelog element + * + * @return string XML data + * + * @access private + */ + function _makeReleaseXml($pkginfo, $changelog = false) + { + $indent = $changelog ? " " : ""; + $ret = "$indent \n"; + if (!empty($pkginfo['version'])) { + $ret .= "$indent $pkginfo[version]\n"; + } + if (!empty($pkginfo['release_date'])) { + $ret .= "$indent $pkginfo[release_date]\n"; + } + if (!empty($pkginfo['release_license'])) { + $ret .= "$indent $pkginfo[release_license]\n"; + } + if (!empty($pkginfo['release_state'])) { + $ret .= "$indent $pkginfo[release_state]\n"; + } + if (!empty($pkginfo['release_notes'])) { + $ret .= "$indent $pkginfo[release_notes]\n"; + } + if (sizeof($pkginfo['release_deps']) > 0) { + $ret .= "$indent \n"; + foreach ($pkginfo['release_deps'] as $dep) { + $ret .= "$indent addTempFile($tmpdir); - if (!$xml || !$tar->extractList($xml, $tmpdir)) { - return $this->raiseError('tgz :: could not extract the package.xml file'); + if (isset($pkginfo['filelist'])) { + $ret .= "$indent \n"; + foreach ($pkginfo['filelist'] as $file => $fa) { + if ($fa['role'] == 'extsrc') { + $ret .= "$indent \n"; + $ret .= "$indent $file\n"; + $ret .= "$indent $fa[sources]\n"; + $ret .= "$indent \n"; + } else { + $ret .= "$indent infoFromDescriptionFile("$tmpdir/$xml"); + $ret .= "$indent \n"; + return $ret; + } // }}} - } } ?> \ No newline at end of file diff --git a/pear/PEAR/Config.php b/pear/PEAR/Config.php index e8b4b610d8..62ad1cdea3 100644 --- a/pear/PEAR/Config.php +++ b/pear/PEAR/Config.php @@ -24,7 +24,7 @@ require_once 'PEAR.php'; * Last created PEAR_Config instance. * @var object */ -$GLOBALS['_PEAR_Config_last_instance'] = null; +$GLOBALS['_PEAR_Config_instance'] = null; define('PEAR_CONFIG_DEFAULT_DOCDIR', PHP_DATADIR.DIRECTORY_SEPARATOR.'pear'.DIRECTORY_SEPARATOR.'doc'); @@ -122,12 +122,22 @@ class PEAR_Config extends PEAR 'default' => 1, 'doc' => 'verbosity level', ), + 'preferred_state' => array( + 'type' => 'set', + 'default' => 'stable', + 'doc' => 'the installer will prefer releases with this state +when installing packages without a version or state specified', + 'valid_set' => array( + 'stable', 'beta', 'alpha', 'devel', 'snapshot', 'any'), + ), +/* 'testset1' => array( 'type' => 'set', 'default' => 'foo', 'doc' => 'test set', 'valid_set' => array('foo', 'bar'), ), +*/ ); // }}} @@ -165,7 +175,6 @@ class PEAR_Config extends PEAR $this->layers = array_keys($this->configuration); $this->files['user'] = $user_file; $this->files['system'] = $system_file; - $GLOBALS['_PEAR_Config_last_instance'] = &$this; if ($user_file && file_exists($user_file)) { $this->readConfigFile($user_file); } @@ -175,6 +184,7 @@ class PEAR_Config extends PEAR foreach ($this->configuration_info as $key => $info) { $this->configuration['default'][$key] = $info['default']; } + //$GLOBALS['_PEAR_Config_instance'] = &$this; } // }}} @@ -197,11 +207,12 @@ class PEAR_Config extends PEAR */ function &singleton($user_file = '', $system_file = '') { - if (empty($GLOBALS['_PEAR_Config_last_instance'])) { - $obj =& new PEAR_Config($user_file, $system_file); - $GLOBALS['_PEAR_Config_last_instance'] = &$obj; + if (is_object($GLOBALS['_PEAR_Config_instance'])) { + return $GLOBALS['_PEAR_Config_instance']; } - return $GLOBALS['_PEAR_Config_last_instance']; + $GLOBALS['_PEAR_Config_instance'] = + &new PEAR_Config($user_file, $system_file); + return $GLOBALS['_PEAR_Config_instance']; } // }}} @@ -318,7 +329,7 @@ class PEAR_Config extends PEAR } $data = $this->configuration[$layer]; $this->_encodeOutput($data); - if (!@is_writeable($file)) { + if (@file_exists($file) && !@is_writeable($file)) { return $this->raiseError("no write access to $file!"); } $fp = @fopen($file, "w"); @@ -354,7 +365,7 @@ class PEAR_Config extends PEAR $size = filesize($file); $contents = fread($fp, $size); $version = '0.1'; - if (preg_match('/^#PEAR_Config\s+(\S+)\s+/si', $contents, &$matches)) { + if (preg_match('/^#PEAR_Config\s+(\S+)\s+/si', $contents, $matches)) { $version = $matches[1]; $contents = substr($contents, strlen($matches[0])); } @@ -446,7 +457,7 @@ class PEAR_Config extends PEAR } // }}} - // {{{ get(key) + // {{{ get(key, [layer]) /** * Returns a configuration value, prioritizing layers as per the @@ -458,12 +469,16 @@ class PEAR_Config extends PEAR * * @access public */ - function get($key) + function get($key, $layer = null) { - foreach ($this->layers as $layer) { - if (isset($this->configuration[$layer][$key])) { - return $this->configuration[$layer][$key]; + if ($layer === null) { + foreach ($this->layers as $layer) { + if (isset($this->configuration[$layer][$key])) { + return $this->configuration[$layer][$key]; + } } + } elseif (isset($this->configuration[$layer][$key])) { + return $this->configuration[$layer][$key]; } return null; } @@ -633,6 +648,23 @@ class PEAR_Config extends PEAR return false; } + // }}} + // {{{ store([layer]) + + /** + * Stores configuration data in a layer. + * + * @param string config layer to store + * + * @return bool TRUE on success, or PEAR error on failure + * + * @access public + */ + function store($layer = 'user') + { + return $this->writeConfigFile(null, $layer); + } + // }}} // {{{ toDefault(key) @@ -716,6 +748,23 @@ class PEAR_Config extends PEAR return false; } + // }}} + // {{{ isDefinedLayer(key) + + /** + * Tells whether a given config layer exists. + * + * @param string config layer + * + * @return bool whether exists in this object + * + * @access public + */ + function isDefinedLayer($layer) + { + return isset($this->configuration[$layer]); + } + // }}} } diff --git a/pear/PEAR/Frontend/CLI.php b/pear/PEAR/Frontend/CLI.php index e8cc5e49e4..ae6d9c0436 100644 --- a/pear/PEAR/Frontend/CLI.php +++ b/pear/PEAR/Frontend/CLI.php @@ -25,14 +25,6 @@ class PEAR_Frontend_CLI extends PEAR { // {{{ properties - /** - * What type of user interface this frontend is for. - * @var string - * @access public - */ - var $type = 'CLI'; - var $lp = ''; // line prefix - var $omode = 'plain'; var $params = array(); var $term = array( @@ -64,28 +56,16 @@ class PEAR_Frontend_CLI extends PEAR // }}} + // For now, all the display functions print a "| " at the + // beginning of the line. This is just a temporary thing, it + // is for discovering commands that use print instead of + // the UI layer. + // {{{ displayLine(text) function displayLine($text) { - print "$this->lp$text\n"; - } - - // }}} - // {{{ displayError(eobj) - - function displayError($eobj) - { - return $this->displayLine($eobj->getMessage()); - } - - // }}} - // {{{ displayFatalError(eobj) - - function displayFatalError($eobj) - { - $this->displayError($eobj); - exit(1); + print "| $text\n"; } // }}} @@ -93,8 +73,8 @@ class PEAR_Frontend_CLI extends PEAR function displayHeading($title) { - print $this->lp.$this->bold($title)."\n"; - print $this->lp.str_repeat("=", strlen($title))."\n"; + print "| ".$this->bold($title)."\n"; + print "| ".str_repeat("=", strlen($title))."\n"; } // }}} @@ -105,7 +85,7 @@ class PEAR_Frontend_CLI extends PEAR if ($type == 'password') { system('stty -echo'); } - print "$this->lp$prompt "; + print "| $prompt "; if ($default) { print "[$default] "; } @@ -130,7 +110,7 @@ class PEAR_Frontend_CLI extends PEAR { static $positives = array('y', 'yes', 'on', '1'); static $negatives = array('n', 'no', 'off', '0'); - print "$this->lp$prompt [$default] : "; + print "| $prompt [$default] : "; $fp = fopen("php://stdin", "r"); $line = fgets($fp, 2048); fclose($fp); diff --git a/pear/PEAR/Installer.php b/pear/PEAR/Installer.php index 260e3e817e..0e9dbdaf19 100644 --- a/pear/PEAR/Installer.php +++ b/pear/PEAR/Installer.php @@ -347,6 +347,10 @@ class PEAR_Installer extends PEAR_Common // Register that the package is installed ----------------------- if (empty($options['upgrade'])) { + // if 'force' is used, replace the info in registry + if (!empty($options['force']) && $this->registry->packageExists($pkgname)) { + $this->registry->deletePackage($pkgname); + } $ret = $this->registry->addPackage($pkgname, $this->pkginfo); } else { $ret = $this->registry->updatePackage($pkgname, $this->pkginfo, false); diff --git a/pear/PEAR/Packager.php b/pear/PEAR/Packager.php index d4fd0c187f..c314e55f8d 100644 --- a/pear/PEAR/Packager.php +++ b/pear/PEAR/Packager.php @@ -26,7 +26,6 @@ require_once 'PEAR/Common.php'; * * TODO: * - add an extra param the dir where to place the created package - * - finish and test Windows support * * @since PHP 4.0.2 * @author Stig Bakken @@ -35,51 +34,16 @@ class PEAR_Packager extends PEAR_Common { // {{{ properties - /** assoc with information about the package */ - var $pkginfo = array(); - - /** name of the package directory, for example Foo-1.0 */ - var $pkgdir; - - /** directory where PHP code files go */ - var $phpdir; - - /** directory where PHP extension files go */ - var $extdir; - - /** directory where documentation goes */ - var $docdir; - - /** directory where system state information goes */ - var $statedir; - /** debug mode (integer) */ var $debug = 0; - /** temporary directory */ - var $tmpdir; - - /** whether file list is currently being copied */ - var $recordfilelist; - - /** temporary space for copying file list */ - var $filelist; - - /** package name and version, for example "HTTP-1.0" */ - var $pkgver; - // }}} // {{{ constructor - function PEAR_Packager($phpdir = PEAR_INSTALL_DIR, - $extdir = PEAR_EXTENSION_DIR, - $docdir = '') + function PEAR_Packager() { $this->PEAR(); - $this->phpdir = $phpdir; - $this->extdir = $extdir; - $this->docdir = $docdir; } // }}} @@ -135,23 +99,41 @@ class PEAR_Packager extends PEAR_Common return $this->raiseError("File $fname does not exist"); } else { $filelist[$i++] = $fname; + if (empty($pkginfo['filelist'][$fname]['md5sum'])) { + $md5sum = md5_file($fname); + $pkginfo['filelist'][$fname]['md5sum'] = $md5sum; + } + $this->log(2, "Adding file $fname"); } } - // XXX TODO: Rebuild the package file as the old method did? + $new_xml = $this->xmlFromInfo($pkginfo); + if (PEAR::isError($new_xml)) { + return $new_xml; + } + $tmpdir = $this->mkTempDir(getcwd()); + $newpkgfile = $tmpdir . DIRECTORY_SEPARATOR . $pkgfile; + $np = @fopen($newpkgfile, "w"); + if (!$np) { + return $this->raiseError("PEAR_Packager: unable to rewrite $pkgfile"); + } + fwrite($np, $new_xml); + fclose($np); // TAR the Package ------------------------------------------- $dest_package = $this->orig_pwd . DIRECTORY_SEPARATOR . "{$pkgver}.tgz"; - $tar = new Archive_Tar($dest_package, true); - $tar->setErrorHandling(PEAR_ERROR_PRINT); + $tar =& new Archive_Tar($dest_package, true); + $tar->setErrorHandling(PEAR_ERROR_RETURN); // XXX Don't print errors // ----- Creates with the package.xml file - if (!$tar->create($pkgfile)) { - return $this->raiseError('an error ocurred during package creation'); + $ok = $tar->createModify($newpkgfile, '', $tmpdir); + if (PEAR::isError($ok)) { + return $ok; + } elseif (!$ok) { + return $this->raiseError('PEAR_Packager: tarball creation failed'); } // ----- Add the content of the package if (!$tar->addModify($filelist, $pkgver)) { - return $this->raiseError('an error ocurred during package creation'); + return $this->raiseError('PEAR_Packager: tarball creation failed'); } - $this->log(1, "Package $dest_package done"); $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $pkgversion); $cvstag = "RELEASE_$cvsversion"; diff --git a/pear/PEAR/Registry.php b/pear/PEAR/Registry.php index d22623e06d..c09e3abddb 100644 --- a/pear/PEAR/Registry.php +++ b/pear/PEAR/Registry.php @@ -19,39 +19,115 @@ // $Id$ require_once "System.php"; +require_once "PEAR.php"; + +define("PEAR_REGISTRY_ERROR_LOCK", -2); /** * Administration class used to maintain the installed package database. */ -class PEAR_Registry +class PEAR_Registry extends PEAR { // {{{ properties - var $statedir; + /** Directory where registry files are stored. + * @var string + */ + var $statedir = ''; + + /** File where the file map is stored + * @var string + */ + var $filemap = ''; + + /** Name of file used for locking the registry + * @var string + */ + var $lockfile = ''; + + /** File descriptor used during locking + * @var resource + */ + var $lock_fp = null; + + /** Mode used during locking + * @var int + */ + var $lock_mode = 0; // XXX UNUSED // }}} // {{{ PEAR_Registry + /** + * PEAR_Registry constructor. + * + * @param string (optional) PEAR install directory (for .php files) + * + * @access public + */ function PEAR_Registry($pear_install_dir = PEAR_INSTALL_DIR) { - $this->statedir = $pear_install_dir . "/.registry"; + parent::PEAR(); + $ds = DIRECTORY_SEPARATOR; + $this->statedir = $pear_install_dir.$ds.'.registry'; + $this->filemap = $pear_install_dir.$ds.'.filemap'; + $this->lockfile = $pear_install_dir.$ds.'.lock'; + if (!file_exists($this->filemap)) { + $this->_rebuildFileMap(); + } + } + + // }}} + // {{{ _PEAR_Registry + + /** + * PEAR_Registry destructor. Makes sure no locks are forgotten. + * + * @access private + */ + function _PEAR_Registry() + { + parent::_PEAR(); + if (is_resource($this->lock_fp)) { + $this->_unlock(); + } } // }}} // {{{ _assertStateDir() + /** + * Make sure the directory where we keep registry files exists. + * + * @return bool TRUE if directory exists, FALSE if it could not be + * created + * + * @access private + */ function _assertStateDir() { if (!@is_dir($this->statedir)) { - System::mkdir("-p {$this->statedir}"); + if (!System::mkdir("-p {$this->statedir}")) { + return $this->raiseError("could not create directory '{$this->statedir}'"); + } } + return true; } // }}} // {{{ _packageFileName() + /** + * Get the name of the file where data for a given package is stored. + * + * @param string package name + * + * @return string registry file name + * + * @access public + */ function _packageFileName($package) { return "{$this->statedir}/{$package}.reg"; @@ -80,41 +156,110 @@ class PEAR_Registry } // }}} + // {{{ _rebuildFileMap() - // {{{ packageExists() - - function packageExists($package) + function _rebuildFileMap() { - return file_exists($this->_packageFileName($package)); + $packages = $this->listPackages(); + $files = array(); + foreach ($packages as $package) { + $version = $this->packageInfo($package, 'version'); + $filelist = $this->packageInfo($package, 'filelist'); + if (!is_array($filelist)) { + continue; + } + foreach ($filelist as $name => $attrs) { + if (isset($attrs['role']) && $attrs['role'] != 'php') { + continue; + } + if (isset($attrs['baseinstalldir'])) { + $file = $attrs['baseinstalldir'].DIRECTORY_SEPARATOR.$name; + } else { + $file = $name; + } + $file = preg_replace(',^/+,', '', $file); + $files[$file] = $package; + } + } + $this->_assertStateDir(); + $fp = @fopen($this->filemap, 'w'); + if (!$fp) { + return false; + } + fwrite($fp, serialize($files)); + fclose($fp); + return true; } // }}} - // {{{ addPackage() + // {{{ _lock() - function addPackage($package, $info) + /** + * Lock the registry. + * + * @param integer lock mode, one of LOCK_EX, LOCK_SH or LOCK_UN. + * See flock manual for more information. + * + * @return bool TRUE on success, FALSE if locking failed, or a + * PEAR error if some other error occurs (such as the + * lock file not being writable). + * + * @access private + */ + function _lock($mode = LOCK_EX) { - if ($this->packageExists($package)) { - return false; + if ($mode != LOCK_UN && is_resource($this->lock_fp)) { + // XXX does not check type of lock (LOCK_SH/LOCK_EX) + return true; } - $fp = $this->_openPackageFile($package, "w"); - if ($fp === null) { - return false; + if (PEAR::isError($err = $this->_assertStateDir())) { + return $err; + } + $this->lock_fp = @fopen($this->lockfile, 'w'); + if (!is_resource($this->lock_fp)) { + return $this->raiseError("could not create lock file: $php_errormsg"); + } + if (!(int)flock($this->lock_fp, $mode)) { + switch ($mode) { + case LOCK_SH: $str = 'shared'; break; + case LOCK_EX: $str = 'exclusive'; break; + case LOCK_UN: $str = 'unlock'; break; + default: $str = 'unknown'; break; + } + return $this->raiseError("could not acquire $str lock ($this->lockfile)", + PEAR_REGISTRY_ERROR_LOCK); } - fwrite($fp, serialize($info)); - $this->_closePackageFile($fp); return true; } // }}} - // {{{ packageInfo() + // {{{ _unlock() - function packageInfo($package = null, $key = null) + function _unlock() + { + $ret = $this->_lock(LOCK_UN); + $this->lock_fp = null; + return $ret; + } + + // }}} + // {{{ _packageExists() + + function _packageExists($package) + { + return file_exists($this->_packageFileName($package)); + } + + // }}} + // {{{ _packageInfo() + + function _packageInfo($package = null, $key = null) { if ($package === null) { - return array_map(array($this, "packageInfo"), - $this->listPackages()); + return array_map(array($this, '_packageInfo'), + $this->_listPackages()); } - $fp = $this->_openPackageFile($package, "r"); + $fp = $this->_openPackageFile($package, 'r'); if ($fp === null) { return null; } @@ -130,13 +275,100 @@ class PEAR_Registry return null; } + // }}} + // {{{ _listPackages() + + function _listPackages() + { + $pkglist = array(); + $dp = @opendir($this->statedir); + if (!$dp) { + return $pkglist; + } + while ($ent = readdir($dp)) { + if ($ent{0} == '.' || substr($ent, -4) != '.reg') { + continue; + } + $pkglist[] = substr($ent, 0, -4); + } + return $pkglist; + } + + // }}} + + // {{{ packageExists() + + function packageExists($package) + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_packageExists($package); + $this->_unlock(); + return $ret; + } + + // }}} + // {{{ packageInfo() + + function packageInfo($package = null, $key = null) + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_packageInfo($package, $key); + $this->_unlock(); + return $ret; + } + + // }}} + // {{{ listPackages() + + function listPackages() + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_listPackages(); + $this->_unlock(); + return $ret; + } + + // }}} + // {{{ addPackage() + + function addPackage($package, $info) + { + if ($this->packageExists($package)) { + return false; + } + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; + } + $fp = $this->_openPackageFile($package, 'w'); + if ($fp === null) { + $this->_unlock(); + return false; + } + fwrite($fp, serialize($info)); + $this->_closePackageFile($fp); + $this->_unlock(); + return true; + } + // }}} // {{{ deletePackage() function deletePackage($package) { + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; + } $file = $this->_packageFileName($package); - return @unlink($file); + $ret = @unlink($file); + $this->_rebuildFileMap(); + $this->_unlock(); + return $ret; } // }}} @@ -148,8 +380,15 @@ class PEAR_Registry if (empty($oldinfo)) { return false; } - $fp = $this->_openPackageFile($package, "w"); + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; + } + if (!file_exists($this->filemap)) { + $this->_rebuildFileMap(); + } + $fp = $this->_openPackageFile($package, 'w'); if ($fp === null) { + $this->_unlock(); return false; } if ($merge) { @@ -158,26 +397,11 @@ class PEAR_Registry fwrite($fp, serialize($info)); } $this->_closePackageFile($fp); - return true; - } - - // }}} - // {{{ listPackages() - - function listPackages() - { - $pkglist = array(); - $dp = @opendir($this->statedir); - if (!$dp) { - return $pkglist; - } - while ($ent = readdir($dp)) { - if ($ent{0} == "." || substr($ent, -4) != ".reg") { - continue; - } - $pkglist[] = substr($ent, 0, -4); + if (isset($info['filelist'])) { + $this->_rebuildFileMap(); } - return $pkglist; + $this->_unlock(); + return true; } // }}} diff --git a/pear/PEAR/Remote.php b/pear/PEAR/Remote.php index 7f397b7221..1f20db6508 100644 --- a/pear/PEAR/Remote.php +++ b/pear/PEAR/Remote.php @@ -19,6 +19,7 @@ // $Id$ require_once 'PEAR.php'; +require_once 'PEAR/Config.php'; /** * This is a class for doing remote operations against the central @@ -28,16 +29,16 @@ class PEAR_Remote extends PEAR { // {{{ properties - var $config_object = null; + var $config = null; // }}} // {{{ PEAR_Remote(config_object) - function PEAR_Remote($config_object) + function PEAR_Remote(&$config) { $this->PEAR(); - $this->config_object = $config_object; + $this->config = $config; } // }}} @@ -51,7 +52,7 @@ class PEAR_Remote extends PEAR } $method = str_replace("_", ".", $method); $request = xmlrpc_encode_request($method, $params); - $server_host = $this->config_object->get("master_server"); + $server_host = $this->config->get("master_server"); if (empty($server_host)) { return $this->raiseError("PEAR_Remote::call: no master_server configured"); } @@ -61,13 +62,34 @@ class PEAR_Remote extends PEAR return $this->raiseError("PEAR_Remote::call: fsockopen(`$server_host', $server_port) failed"); } $len = strlen($request); - fwrite($fp, ("POST /xmlrpc.php HTTP/1.0\r\n". - "Host: $server_host:$server_port\r\n". - "Content-type: text/xml\r\n". - "Content-length: $len\r\n". - "\r\n$request")); + $req_headers = "Host: $server_host:$server_port\r\n" . + "Content-type: text/xml\r\n" . + "Content-length: $len\r\n"; + $username = $this->config->get('username'); + $password = $this->config->get('password'); + if ($username && $password) { + $tmp = base64_encode("$username:$password"); + $req_headers .= "Authorization: Basic $tmp\r\n"; + } + fwrite($fp, ("POST /xmlrpc.php HTTP/1.0\r\n$req_headers\r\n$request")); $response = ''; - while (trim(fgets($fp, 2048)) != ''); // skip headers + $line1 = fgets($fp, 2048); + if (!preg_match('!^HTTP/[0-9\.]+ (\d+) (.*)!', $line1, $matches)) { + return $this->raiseError("PEAR_Remote: invalid HTTP response from XML-RPC server"); + } + switch ($matches[1]) { + case "200": + break; + case "401": + if ($username && $password) { + return $this->raiseError("PEAR_Remote: authorization failed", 401); + } else { + return $this->raiseError("PEAR_Remote: authorization required, please log in first", 401); + } + default: + return $this->raiseError("PEAR_Remote: unexpected HTTP response", (int)$matches[1], null, null, "$matches[1] $matches[2]"); + } + while (trim(fgets($fp, 2048)) != ''); // skip rest of headers while ($chunk = fread($fp, 10240)) { $response .= $chunk; } @@ -85,13 +107,20 @@ class PEAR_Remote extends PEAR if ($ret['userinfo'] === '') $ret['userinfo'] = null; if (strtolower($class) == 'db_error') { $ret = $this->raiseError(DB::errorMessage($ret['code']), - $ret['code'], null, null, - $ret['userinfo']); + $ret['code'], null, null, + $ret['userinfo']); } else { $ret = $this->raiseError($ret['message'], $ret['code'], - null, null, $ret['userinfo']); + null, null, $ret['userinfo']); } } + } elseif (is_array($ret) && sizeof($ret) == 1 && + isset($ret[0]['faultString']) && + isset($ret[0]['faultCode'])) { + extract($ret[0]); + $faultString = "XML-RPC Server Fault: " . + str_replace("\n", " ", $faultString); + return $this->raiseError($faultString, $faultCode); } return $ret; } diff --git a/pear/package.dtd b/pear/package.dtd index fce939283a..a0cb045559 100644 --- a/pear/package.dtd +++ b/pear/package.dtd @@ -1,10 +1,10 @@