Rev 187 | Blame | Compare with Previous | Last modification | View Log | RSS feed
<?php/*** PEAR_Registry** PHP versions 4 and 5** @category pear* @package PEAR* @author Stig Bakken <ssb@php.net>* @author Tomas V. V. Cox <cox@idecnet.com>* @author Greg Beaver <cellog@php.net>* @copyright 1997-2009 The Authors* @license http://opensource.org/licenses/bsd-license.php New BSD License* @link http://pear.php.net/package/PEAR* @since File available since Release 0.1*//*** for PEAR_Error*/require_once 'PEAR.php';require_once 'PEAR/DependencyDB.php';define('PEAR_REGISTRY_ERROR_LOCK', -2);define('PEAR_REGISTRY_ERROR_FORMAT', -3);define('PEAR_REGISTRY_ERROR_FILE', -4);define('PEAR_REGISTRY_ERROR_CONFLICT', -5);define('PEAR_REGISTRY_ERROR_CHANNEL_FILE', -6);/*** Administration class used to maintain the installed package database.* @category pear* @package PEAR* @author Stig Bakken <ssb@php.net>* @author Tomas V. V. Cox <cox@idecnet.com>* @author Greg Beaver <cellog@php.net>* @copyright 1997-2009 The Authors* @license http://opensource.org/licenses/bsd-license.php New BSD License* @version Release: 1.10.1* @link http://pear.php.net/package/PEAR* @since Class available since Release 1.4.0a1*/class PEAR_Registry extends PEAR{/*** File containing all channel information.* @var string*/var $channels = '';/** Directory where registry files are stored.* @var string*/var $statedir = '';/** File where the file map is stored* @var string*/var $filemap = '';/** Directory where registry files for channels are stored.* @var string*/var $channelsdir = '';/** 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/** Cache of package information. Structure:* array(* 'package' => array('id' => ... ),* ... )* @var array*/var $pkginfo_cache = array();/** Cache of file map. Structure:* array( '/path/to/file' => 'package', ... )* @var array*/var $filemap_cache = array();/*** @var false|PEAR_ChannelFile*/var $_pearChannel;/*** @var false|PEAR_ChannelFile*/var $_peclChannel;/*** @var false|PEAR_ChannelFile*/var $_docChannel;/*** @var PEAR_DependencyDB*/var $_dependencyDB;/*** @var PEAR_Config*/var $_config;/*** PEAR_Registry constructor.** @param string (optional) PEAR install directory (for .php files)* @param PEAR_ChannelFile PEAR_ChannelFile object representing the PEAR channel, if* default values are not desired. Only used the very first time a PEAR* repository is initialized* @param PEAR_ChannelFile PEAR_ChannelFile object representing the PECL channel, if* default values are not desired. Only used the very first time a PEAR* repository is initialized** @access public*/function __construct($pear_install_dir = PEAR_INSTALL_DIR, $pear_channel = false,$pecl_channel = false, $pear_metadata_dir = ''){parent::__construct();$this->setInstallDir($pear_install_dir, $pear_metadata_dir);$this->_pearChannel = $pear_channel;$this->_peclChannel = $pecl_channel;$this->_config = false;}function setInstallDir($pear_install_dir = PEAR_INSTALL_DIR, $pear_metadata_dir = ''){$ds = DIRECTORY_SEPARATOR;$this->install_dir = $pear_install_dir;if (!$pear_metadata_dir) {$pear_metadata_dir = $pear_install_dir;}$this->channelsdir = $pear_metadata_dir.$ds.'.channels';$this->statedir = $pear_metadata_dir.$ds.'.registry';$this->filemap = $pear_metadata_dir.$ds.'.filemap';$this->lockfile = $pear_metadata_dir.$ds.'.lock';}function hasWriteAccess(){if (!file_exists($this->install_dir)) {$dir = $this->install_dir;while ($dir && $dir != '.') {$olddir = $dir;$dir = dirname($dir);if ($dir != '.' && file_exists($dir)) {if (is_writeable($dir)) {return true;}return false;}if ($dir == $olddir) { // this can happen in safe modereturn @is_writable($dir);}}return false;}return is_writeable($this->install_dir);}function setConfig(&$config, $resetInstallDir = true){$this->_config = &$config;if ($resetInstallDir) {$this->setInstallDir($config->get('php_dir'), $config->get('metadata_dir'));}}function _initializeChannelDirs(){static $running = false;if (!$running) {$running = true;$ds = DIRECTORY_SEPARATOR;if (!is_dir($this->channelsdir) ||!file_exists($this->channelsdir . $ds . 'pear.php.net.reg') ||!file_exists($this->channelsdir . $ds . 'pecl.php.net.reg') ||!file_exists($this->channelsdir . $ds . 'doc.php.net.reg') ||!file_exists($this->channelsdir . $ds . '__uri.reg')) {if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) {$pear_channel = $this->_pearChannel;if (!is_a($pear_channel, 'PEAR_ChannelFile') || !$pear_channel->validate()) {if (!class_exists('PEAR_ChannelFile')) {require_once 'PEAR/ChannelFile.php';}$pear_channel = new PEAR_ChannelFile;$pear_channel->setAlias('pear');$pear_channel->setServer('pear.php.net');$pear_channel->setSummary('PHP Extension and Application Repository');$pear_channel->setDefaultPEARProtocols();$pear_channel->setBaseURL('REST1.0', 'http://pear.php.net/rest/');$pear_channel->setBaseURL('REST1.1', 'http://pear.php.net/rest/');$pear_channel->setBaseURL('REST1.3', 'http://pear.php.net/rest/');//$pear_channel->setBaseURL('REST1.4', 'http://pear.php.net/rest/');} else {$pear_channel->setServer('pear.php.net');$pear_channel->setAlias('pear');}$pear_channel->validate();$this->_addChannel($pear_channel);}if (!file_exists($this->channelsdir . $ds . 'pecl.php.net.reg')) {$pecl_channel = $this->_peclChannel;if (!is_a($pecl_channel, 'PEAR_ChannelFile') || !$pecl_channel->validate()) {if (!class_exists('PEAR_ChannelFile')) {require_once 'PEAR/ChannelFile.php';}$pecl_channel = new PEAR_ChannelFile;$pecl_channel->setAlias('pecl');$pecl_channel->setServer('pecl.php.net');$pecl_channel->setSummary('PHP Extension Community Library');$pecl_channel->setDefaultPEARProtocols();$pecl_channel->setBaseURL('REST1.0', 'http://pecl.php.net/rest/');$pecl_channel->setBaseURL('REST1.1', 'http://pecl.php.net/rest/');$pecl_channel->setValidationPackage('PEAR_Validator_PECL', '1.0');} else {$pecl_channel->setServer('pecl.php.net');$pecl_channel->setAlias('pecl');}$pecl_channel->validate();$this->_addChannel($pecl_channel);}if (!file_exists($this->channelsdir . $ds . 'doc.php.net.reg')) {$doc_channel = $this->_docChannel;if (!is_a($doc_channel, 'PEAR_ChannelFile') || !$doc_channel->validate()) {if (!class_exists('PEAR_ChannelFile')) {require_once 'PEAR/ChannelFile.php';}$doc_channel = new PEAR_ChannelFile;$doc_channel->setAlias('phpdocs');$doc_channel->setServer('doc.php.net');$doc_channel->setSummary('PHP Documentation Team');$doc_channel->setDefaultPEARProtocols();$doc_channel->setBaseURL('REST1.0', 'http://doc.php.net/rest/');$doc_channel->setBaseURL('REST1.1', 'http://doc.php.net/rest/');$doc_channel->setBaseURL('REST1.3', 'http://doc.php.net/rest/');} else {$doc_channel->setServer('doc.php.net');$doc_channel->setAlias('doc');}$doc_channel->validate();$this->_addChannel($doc_channel);}if (!file_exists($this->channelsdir . $ds . '__uri.reg')) {if (!class_exists('PEAR_ChannelFile')) {require_once 'PEAR/ChannelFile.php';}$private = new PEAR_ChannelFile;$private->setName('__uri');$private->setDefaultPEARProtocols();$private->setBaseURL('REST1.0', '****');$private->setSummary('Pseudo-channel for static packages');$this->_addChannel($private);}$this->_rebuildFileMap();}$running = false;}}function _initializeDirs(){$ds = DIRECTORY_SEPARATOR;// XXX Compatibility code should be removed in the future// rename all registry files if any to lowercaseif (!OS_WINDOWS && file_exists($this->statedir) && is_dir($this->statedir) &&$handle = opendir($this->statedir)) {$dest = $this->statedir . $ds;while (false !== ($file = readdir($handle))) {if (preg_match('/^.*[A-Z].*\.reg\\z/', $file)) {rename($dest . $file, $dest . strtolower($file));}}closedir($handle);}$this->_initializeChannelDirs();if (!file_exists($this->filemap)) {$this->_rebuildFileMap();}$this->_initializeDepDB();}function _initializeDepDB(){if (!isset($this->_dependencyDB)) {static $initializing = false;if (!$initializing) {$initializing = true;if (!$this->_config) { // never used?$file = OS_WINDOWS ? 'pear.ini' : '.pearrc';$this->_config = new PEAR_Config($this->statedir . DIRECTORY_SEPARATOR .$file);$this->_config->setRegistry($this);$this->_config->set('php_dir', $this->install_dir);}$this->_dependencyDB = &PEAR_DependencyDB::singleton($this->_config);if (PEAR::isError($this->_dependencyDB)) {// attempt to recover by removing the dep dbif (file_exists($this->_config->get('metadata_dir', null, 'pear.php.net') .DIRECTORY_SEPARATOR . '.depdb')) {@unlink($this->_config->get('metadata_dir', null, 'pear.php.net') .DIRECTORY_SEPARATOR . '.depdb');}$this->_dependencyDB = &PEAR_DependencyDB::singleton($this->_config);if (PEAR::isError($this->_dependencyDB)) {echo $this->_dependencyDB->getMessage();echo 'Unrecoverable error';exit(1);}}$initializing = false;}}}/*** PEAR_Registry destructor. Makes sure no locks are forgotten.** @access private*/function _PEAR_Registry(){parent::_PEAR();if (is_resource($this->lock_fp)) {$this->_unlock();}}/*** 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($channel = false){if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') {return $this->_assertChannelStateDir($channel);}static $init = false;if (!file_exists($this->statedir)) {if (!$this->hasWriteAccess()) {return false;}require_once 'System.php';if (!System::mkdir(array('-p', $this->statedir))) {return $this->raiseError("could not create directory '{$this->statedir}'");}$init = true;} elseif (!is_dir($this->statedir)) {return $this->raiseError('Cannot create directory ' . $this->statedir . ', ' .'it already exists and is not a directory');}$ds = DIRECTORY_SEPARATOR;if (!file_exists($this->channelsdir)) {if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg') ||!file_exists($this->channelsdir . $ds . 'pecl.php.net.reg') ||!file_exists($this->channelsdir . $ds . 'doc.php.net.reg') ||!file_exists($this->channelsdir . $ds . '__uri.reg')) {$init = true;}} elseif (!is_dir($this->channelsdir)) {return $this->raiseError('Cannot create directory ' . $this->channelsdir . ', ' .'it already exists and is not a directory');}if ($init) {static $running = false;if (!$running) {$running = true;$this->_initializeDirs();$running = false;$init = false;}} else {$this->_initializeDepDB();}return true;}/*** Make sure the directory where we keep registry files exists for a non-standard channel.** @param string channel name* @return bool TRUE if directory exists, FALSE if it could not be* created** @access private*/function _assertChannelStateDir($channel){$ds = DIRECTORY_SEPARATOR;if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') {if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) {$this->_initializeChannelDirs();}return $this->_assertStateDir($channel);}$channelDir = $this->_channelDirectoryName($channel);if (!is_dir($this->channelsdir) ||!file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) {$this->_initializeChannelDirs();}if (!file_exists($channelDir)) {if (!$this->hasWriteAccess()) {return false;}require_once 'System.php';if (!System::mkdir(array('-p', $channelDir))) {return $this->raiseError("could not create directory '" . $channelDir ."'");}} elseif (!is_dir($channelDir)) {return $this->raiseError("could not create directory '" . $channelDir ."', already exists and is not a directory");}return true;}/*** Make sure the directory where we keep registry files for channels exists** @return bool TRUE if directory exists, FALSE if it could not be* created** @access private*/function _assertChannelDir(){if (!file_exists($this->channelsdir)) {if (!$this->hasWriteAccess()) {return false;}require_once 'System.php';if (!System::mkdir(array('-p', $this->channelsdir))) {return $this->raiseError("could not create directory '{$this->channelsdir}'");}} elseif (!is_dir($this->channelsdir)) {return $this->raiseError("could not create directory '{$this->channelsdir}" ."', it already exists and is not a directory");}if (!file_exists($this->channelsdir . DIRECTORY_SEPARATOR . '.alias')) {if (!$this->hasWriteAccess()) {return false;}require_once 'System.php';if (!System::mkdir(array('-p', $this->channelsdir . DIRECTORY_SEPARATOR . '.alias'))) {return $this->raiseError("could not create directory '{$this->channelsdir}/.alias'");}} elseif (!is_dir($this->channelsdir . DIRECTORY_SEPARATOR . '.alias')) {return $this->raiseError("could not create directory '{$this->channelsdir}" ."/.alias', it already exists and is not a directory");}return true;}/*** Get the name of the file where data for a given package is stored.** @param string channel name, or false if this is a PEAR package* @param string package name** @return string registry file name** @access public*/function _packageFileName($package, $channel = false){if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') {return $this->_channelDirectoryName($channel) . DIRECTORY_SEPARATOR .strtolower($package) . '.reg';}return $this->statedir . DIRECTORY_SEPARATOR . strtolower($package) . '.reg';}/*** Get the name of the file where data for a given channel is stored.* @param string channel name* @return string registry file name*/function _channelFileName($channel, $noaliases = false){if (!$noaliases) {if (file_exists($this->_getChannelAliasFileName($channel))) {$channel = implode('', file($this->_getChannelAliasFileName($channel)));}}return $this->channelsdir . DIRECTORY_SEPARATOR . str_replace('/', '_',strtolower($channel)) . '.reg';}/*** @param string* @return string*/function _getChannelAliasFileName($alias){return $this->channelsdir . DIRECTORY_SEPARATOR . '.alias' .DIRECTORY_SEPARATOR . str_replace('/', '_', strtolower($alias)) . '.txt';}/*** Get the name of a channel from its alias*/function _getChannelFromAlias($channel){if (!$this->_channelExists($channel)) {if ($channel == 'pear.php.net') {return 'pear.php.net';}if ($channel == 'pecl.php.net') {return 'pecl.php.net';}if ($channel == 'doc.php.net') {return 'doc.php.net';}if ($channel == '__uri') {return '__uri';}return false;}$channel = strtolower($channel);if (file_exists($this->_getChannelAliasFileName($channel))) {// translate an alias to an actual channelreturn implode('', file($this->_getChannelAliasFileName($channel)));}return $channel;}/*** Get the alias of a channel from its alias or its name*/function _getAlias($channel){if (!$this->_channelExists($channel)) {if ($channel == 'pear.php.net') {return 'pear';}if ($channel == 'pecl.php.net') {return 'pecl';}if ($channel == 'doc.php.net') {return 'phpdocs';}return false;}$channel = $this->_getChannel($channel);if (PEAR::isError($channel)) {return $channel;}return $channel->getAlias();}/*** Get the name of the file where data for a given package is stored.** @param string channel name, or false if this is a PEAR package* @param string package name** @return string registry file name** @access public*/function _channelDirectoryName($channel){if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') {return $this->statedir;}$ch = $this->_getChannelFromAlias($channel);if (!$ch) {$ch = $channel;}return $this->statedir . DIRECTORY_SEPARATOR . strtolower('.channel.' .str_replace('/', '_', $ch));}function _openPackageFile($package, $mode, $channel = false){if (!$this->_assertStateDir($channel)) {return null;}if (!in_array($mode, array('r', 'rb')) && !$this->hasWriteAccess()) {return null;}$file = $this->_packageFileName($package, $channel);if (!file_exists($file) && $mode == 'r' || $mode == 'rb') {return null;}$fp = @fopen($file, $mode);if (!$fp) {return null;}return $fp;}function _closePackageFile($fp){fclose($fp);}function _openChannelFile($channel, $mode){if (!$this->_assertChannelDir()) {return null;}if (!in_array($mode, array('r', 'rb')) && !$this->hasWriteAccess()) {return null;}$file = $this->_channelFileName($channel);if (!file_exists($file) && $mode == 'r' || $mode == 'rb') {return null;}$fp = @fopen($file, $mode);if (!$fp) {return null;}return $fp;}function _closeChannelFile($fp){fclose($fp);}function _rebuildFileMap(){if (!class_exists('PEAR_Installer_Role')) {require_once 'PEAR/Installer/Role.php';}$channels = $this->_listAllPackages();$files = array();foreach ($channels as $channel => $packages) {foreach ($packages as $package) {$version = $this->_packageInfo($package, 'version', $channel);$filelist = $this->_packageInfo($package, 'filelist', $channel);if (!is_array($filelist)) {continue;}foreach ($filelist as $name => $attrs) {if (isset($attrs['attribs'])) {$attrs = $attrs['attribs'];}// it is possible for conflicting packages in different channels to// conflict with data files/doc filesif ($name == 'dirtree') {continue;}if (isset($attrs['role']) && !in_array($attrs['role'],PEAR_Installer_Role::getInstallableRoles())) {// these are not installedcontinue;}if (isset($attrs['role']) && !in_array($attrs['role'],PEAR_Installer_Role::getBaseinstallRoles())) {$attrs['baseinstalldir'] = $package;}if (isset($attrs['baseinstalldir'])) {$file = $attrs['baseinstalldir'].DIRECTORY_SEPARATOR.$name;} else {$file = $name;}$file = preg_replace(',^/+,', '', $file);if ($channel != 'pear.php.net') {if (!isset($files[$attrs['role']])) {$files[$attrs['role']] = array();}$files[$attrs['role']][$file] = array(strtolower($channel),strtolower($package));} else {if (!isset($files[$attrs['role']])) {$files[$attrs['role']] = array();}$files[$attrs['role']][$file] = strtolower($package);}}}}$this->_assertStateDir();if (!$this->hasWriteAccess()) {return false;}$fp = @fopen($this->filemap, 'wb');if (!$fp) {return false;}$this->filemap_cache = $files;fwrite($fp, serialize($files));fclose($fp);return true;}function _readFileMap(){if (!file_exists($this->filemap)) {return array();}$fp = @fopen($this->filemap, 'r');if (!$fp) {return $this->raiseError('PEAR_Registry: could not open filemap "' . $this->filemap . '"', PEAR_REGISTRY_ERROR_FILE, null, null, $php_errormsg);}clearstatcache();$fsize = filesize($this->filemap);fclose($fp);$data = file_get_contents($this->filemap);$tmp = unserialize($data);if (!$tmp && $fsize > 7) {return $this->raiseError('PEAR_Registry: invalid filemap data', PEAR_REGISTRY_ERROR_FORMAT, null, null, $data);}$this->filemap_cache = $tmp;return true;}/*** 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 (stristr(php_uname(), 'Windows 9')) {return true;}if ($mode != LOCK_UN && is_resource($this->lock_fp)) {// XXX does not check type of lock (LOCK_SH/LOCK_EX)return true;}if (!$this->_assertStateDir()) {if ($mode == LOCK_EX) {return $this->raiseError('Registry directory is not writeable by the current user');}return true;}$open_mode = 'w';// XXX People reported problems with LOCK_SH and 'w'if ($mode === LOCK_SH || $mode === LOCK_UN) {if (!file_exists($this->lockfile)) {touch($this->lockfile);}$open_mode = 'r';}if (!is_resource($this->lock_fp)) {$this->lock_fp = @fopen($this->lockfile, $open_mode);}if (!is_resource($this->lock_fp)) {$this->lock_fp = null;return $this->raiseError("could not create lock file" .(isset($php_errormsg) ? ": " . $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;}//is resource at this point, close it on error.fclose($this->lock_fp);$this->lock_fp = null;return $this->raiseError("could not acquire $str lock ($this->lockfile)",PEAR_REGISTRY_ERROR_LOCK);}return true;}function _unlock(){$ret = $this->_lock(LOCK_UN);if (is_resource($this->lock_fp)) {fclose($this->lock_fp);}$this->lock_fp = null;return $ret;}function _packageExists($package, $channel = false){return file_exists($this->_packageFileName($package, $channel));}/*** Determine whether a channel exists in the registry** @param string Channel name* @param bool if true, then aliases will be ignored* @return boolean*/function _channelExists($channel, $noaliases = false){$a = file_exists($this->_channelFileName($channel, $noaliases));if (!$a && $channel == 'pear.php.net') {return true;}if (!$a && $channel == 'pecl.php.net') {return true;}if (!$a && $channel == 'doc.php.net') {return true;}return $a;}/*** Determine whether a mirror exists within the deafult channel in the registry** @param string Channel name* @param string Mirror name** @return boolean*/function _mirrorExists($channel, $mirror){$data = $this->_channelInfo($channel);if (!isset($data['servers']['mirror'])) {return false;}foreach ($data['servers']['mirror'] as $m) {if ($m['attribs']['host'] == $mirror) {return true;}}return false;}/*** @param PEAR_ChannelFile Channel object* @param donotuse* @param string Last-Modified HTTP tag from remote request* @return boolean|PEAR_Error True on creation, false if it already exists*/function _addChannel($channel, $update = false, $lastmodified = false){if (!is_a($channel, 'PEAR_ChannelFile')) {return false;}if (!$channel->validate()) {return false;}if (file_exists($this->_channelFileName($channel->getName()))) {if (!$update) {return false;}$checker = $this->_getChannel($channel->getName());if (PEAR::isError($checker)) {return $checker;}if ($channel->getAlias() != $checker->getAlias()) {if (file_exists($this->_getChannelAliasFileName($checker->getAlias()))) {@unlink($this->_getChannelAliasFileName($checker->getAlias()));}}} else {if ($update && !in_array($channel->getName(), array('pear.php.net', 'pecl.php.net', 'doc.php.net'))) {return false;}}$ret = $this->_assertChannelDir();if (PEAR::isError($ret)) {return $ret;}$ret = $this->_assertChannelStateDir($channel->getName());if (PEAR::isError($ret)) {return $ret;}if ($channel->getAlias() != $channel->getName()) {if (file_exists($this->_getChannelAliasFileName($channel->getAlias())) &&$this->_getChannelFromAlias($channel->getAlias()) != $channel->getName()) {$channel->setAlias($channel->getName());}if (!$this->hasWriteAccess()) {return false;}$fp = @fopen($this->_getChannelAliasFileName($channel->getAlias()), 'w');if (!$fp) {return false;}fwrite($fp, $channel->getName());fclose($fp);}if (!$this->hasWriteAccess()) {return false;}$fp = @fopen($this->_channelFileName($channel->getName()), 'wb');if (!$fp) {return false;}$info = $channel->toArray();if ($lastmodified) {$info['_lastmodified'] = $lastmodified;} else {$info['_lastmodified'] = date('r');}fwrite($fp, serialize($info));fclose($fp);return true;}/*** Deletion fails if there are any packages installed from the channel* @param string|PEAR_ChannelFile channel name* @return boolean|PEAR_Error True on deletion, false if it doesn't exist*/function _deleteChannel($channel){if (!is_string($channel)) {if (!is_a($channel, 'PEAR_ChannelFile')) {return false;}if (!$channel->validate()) {return false;}$channel = $channel->getName();}if ($this->_getChannelFromAlias($channel) == '__uri') {return false;}if ($this->_getChannelFromAlias($channel) == 'pecl.php.net') {return false;}if ($this->_getChannelFromAlias($channel) == 'doc.php.net') {return false;}if (!$this->_channelExists($channel)) {return false;}if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') {return false;}$channel = $this->_getChannelFromAlias($channel);if ($channel == 'pear.php.net') {return false;}$test = $this->_listChannelPackages($channel);if (count($test)) {return false;}$test = @rmdir($this->_channelDirectoryName($channel));if (!$test) {return false;}$file = $this->_getChannelAliasFileName($this->_getAlias($channel));if (file_exists($file)) {$test = @unlink($file);if (!$test) {return false;}}$file = $this->_channelFileName($channel);$ret = true;if (file_exists($file)) {$ret = @unlink($file);}return $ret;}/*** Determine whether a channel exists in the registry* @param string Channel Alias* @return boolean*/function _isChannelAlias($alias){return file_exists($this->_getChannelAliasFileName($alias));}/*** @param string|null* @param string|null* @param string|null* @return array|null* @access private*/function _packageInfo($package = null, $key = null, $channel = 'pear.php.net'){if ($package === null) {if ($channel === null) {$channels = $this->_listChannels();$ret = array();foreach ($channels as $channel) {$channel = strtolower($channel);$ret[$channel] = array();$packages = $this->_listPackages($channel);foreach ($packages as $package) {$ret[$channel][] = $this->_packageInfo($package, null, $channel);}}return $ret;}$ps = $this->_listPackages($channel);if (!count($ps)) {return array();}return array_map(array(&$this, '_packageInfo'),$ps, array_fill(0, count($ps), null),array_fill(0, count($ps), $channel));}$fp = $this->_openPackageFile($package, 'r', $channel);if ($fp === null) {return null;}clearstatcache();$this->_closePackageFile($fp);$data = file_get_contents($this->_packageFileName($package, $channel));$data = unserialize($data);if ($key === null) {return $data;}// compatibility for package.xml version 2.0if (isset($data['old'][$key])) {return $data['old'][$key];}if (isset($data[$key])) {return $data[$key];}return null;}/*** @param string Channel name* @param bool whether to strictly retrieve info of channels, not just aliases* @return array|null*/function _channelInfo($channel, $noaliases = false){if (!$this->_channelExists($channel, $noaliases)) {return null;}$fp = $this->_openChannelFile($channel, 'r');if ($fp === null) {return null;}clearstatcache();$this->_closeChannelFile($fp);$data = file_get_contents($this->_channelFileName($channel));$data = unserialize($data);return $data;}function _listChannels(){$channellist = array();if (!file_exists($this->channelsdir) || !is_dir($this->channelsdir)) {return array('pear.php.net', 'pecl.php.net', 'doc.php.net', '__uri');}$dp = opendir($this->channelsdir);while ($ent = readdir($dp)) {if ($ent{0} == '.' || substr($ent, -4) != '.reg') {continue;}if ($ent == '__uri.reg') {$channellist[] = '__uri';continue;}$channellist[] = str_replace('_', '/', substr($ent, 0, -4));}closedir($dp);if (!in_array('pear.php.net', $channellist)) {$channellist[] = 'pear.php.net';}if (!in_array('pecl.php.net', $channellist)) {$channellist[] = 'pecl.php.net';}if (!in_array('doc.php.net', $channellist)) {$channellist[] = 'doc.php.net';}if (!in_array('__uri', $channellist)) {$channellist[] = '__uri';}natsort($channellist);return $channellist;}function _listPackages($channel = false){if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') {return $this->_listChannelPackages($channel);}if (!file_exists($this->statedir) || !is_dir($this->statedir)) {return array();}$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);}closedir($dp);return $pkglist;}function _listChannelPackages($channel){$pkglist = array();if (!file_exists($this->_channelDirectoryName($channel)) ||!is_dir($this->_channelDirectoryName($channel))) {return array();}$dp = opendir($this->_channelDirectoryName($channel));if (!$dp) {return $pkglist;}while ($ent = readdir($dp)) {if ($ent{0} == '.' || substr($ent, -4) != '.reg') {continue;}$pkglist[] = substr($ent, 0, -4);}closedir($dp);return $pkglist;}function _listAllPackages(){$ret = array();foreach ($this->_listChannels() as $channel) {$ret[$channel] = $this->_listPackages($channel);}return $ret;}/*** Add an installed package to the registry* @param string package name* @param array package info (parsed by PEAR_Common::infoFrom*() methods)* @return bool success of saving* @access private*/function _addPackage($package, $info){if ($this->_packageExists($package)) {return false;}$fp = $this->_openPackageFile($package, 'wb');if ($fp === null) {return false;}$info['_lastmodified'] = time();fwrite($fp, serialize($info));$this->_closePackageFile($fp);if (isset($info['filelist'])) {$this->_rebuildFileMap();}return true;}/*** @param PEAR_PackageFile_v1|PEAR_PackageFile_v2* @return bool* @access private*/function _addPackage2($info){if (!is_a($info, 'PEAR_PackageFile_v1') && !is_a($info, 'PEAR_PackageFile_v2')) {return false;}if (!$info->validate()) {if (class_exists('PEAR_Common')) {$ui = PEAR_Frontend::singleton();if ($ui) {foreach ($info->getValidationWarnings() as $err) {$ui->log($err['message'], true);}}}return false;}$channel = $info->getChannel();$package = $info->getPackage();$save = $info;if ($this->_packageExists($package, $channel)) {return false;}if (!$this->_channelExists($channel, true)) {return false;}$info = $info->toArray(true);if (!$info) {return false;}$fp = $this->_openPackageFile($package, 'wb', $channel);if ($fp === null) {return false;}$info['_lastmodified'] = time();fwrite($fp, serialize($info));$this->_closePackageFile($fp);$this->_rebuildFileMap();return true;}/*** @param string Package name* @param array parsed package.xml 1.0* @param bool this parameter is only here for BC. Don't use it.* @access private*/function _updatePackage($package, $info, $merge = true){$oldinfo = $this->_packageInfo($package);if (empty($oldinfo)) {return false;}$fp = $this->_openPackageFile($package, 'w');if ($fp === null) {return false;}if (is_object($info)) {$info = $info->toArray();}$info['_lastmodified'] = time();$newinfo = $info;if ($merge) {$info = array_merge($oldinfo, $info);} else {$diff = $info;}fwrite($fp, serialize($info));$this->_closePackageFile($fp);if (isset($newinfo['filelist'])) {$this->_rebuildFileMap();}return true;}/*** @param PEAR_PackageFile_v1|PEAR_PackageFile_v2* @return bool* @access private*/function _updatePackage2($info){if (!$this->_packageExists($info->getPackage(), $info->getChannel())) {return false;}$fp = $this->_openPackageFile($info->getPackage(), 'w', $info->getChannel());if ($fp === null) {return false;}$save = $info;$info = $save->getArray(true);$info['_lastmodified'] = time();fwrite($fp, serialize($info));$this->_closePackageFile($fp);$this->_rebuildFileMap();return true;}/*** @param string Package name* @param string Channel name* @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|null* @access private*/function &_getPackage($package, $channel = 'pear.php.net'){$info = $this->_packageInfo($package, null, $channel);if ($info === null) {return $info;}$a = $this->_config;if (!$a) {$this->_config = new PEAR_Config;$this->_config->set('php_dir', $this->statedir);}if (!class_exists('PEAR_PackageFile')) {require_once 'PEAR/PackageFile.php';}$pkg = new PEAR_PackageFile($this->_config);$pf = &$pkg->fromArray($info);return $pf;}/*** @param string channel name* @param bool whether to strictly retrieve channel names* @return PEAR_ChannelFile|PEAR_Error* @access private*/function &_getChannel($channel, $noaliases = false){$ch = false;if ($this->_channelExists($channel, $noaliases)) {$chinfo = $this->_channelInfo($channel, $noaliases);if ($chinfo) {if (!class_exists('PEAR_ChannelFile')) {require_once 'PEAR/ChannelFile.php';}$ch = &PEAR_ChannelFile::fromArrayWithErrors($chinfo);}}if ($ch) {if ($ch->validate()) {return $ch;}foreach ($ch->getErrors(true) as $err) {$message = $err['message'] . "\n";}$ch = PEAR::raiseError($message);return $ch;}if ($this->_getChannelFromAlias($channel) == 'pear.php.net') {// the registry is not properly set up, so use defaultsif (!class_exists('PEAR_ChannelFile')) {require_once 'PEAR/ChannelFile.php';}$pear_channel = new PEAR_ChannelFile;$pear_channel->setServer('pear.php.net');$pear_channel->setAlias('pear');$pear_channel->setSummary('PHP Extension and Application Repository');$pear_channel->setDefaultPEARProtocols();$pear_channel->setBaseURL('REST1.0', 'http://pear.php.net/rest/');$pear_channel->setBaseURL('REST1.1', 'http://pear.php.net/rest/');$pear_channel->setBaseURL('REST1.3', 'http://pear.php.net/rest/');return $pear_channel;}if ($this->_getChannelFromAlias($channel) == 'pecl.php.net') {// the registry is not properly set up, so use defaultsif (!class_exists('PEAR_ChannelFile')) {require_once 'PEAR/ChannelFile.php';}$pear_channel = new PEAR_ChannelFile;$pear_channel->setServer('pecl.php.net');$pear_channel->setAlias('pecl');$pear_channel->setSummary('PHP Extension Community Library');$pear_channel->setDefaultPEARProtocols();$pear_channel->setBaseURL('REST1.0', 'http://pecl.php.net/rest/');$pear_channel->setBaseURL('REST1.1', 'http://pecl.php.net/rest/');$pear_channel->setValidationPackage('PEAR_Validator_PECL', '1.0');return $pear_channel;}if ($this->_getChannelFromAlias($channel) == 'doc.php.net') {// the registry is not properly set up, so use defaultsif (!class_exists('PEAR_ChannelFile')) {require_once 'PEAR/ChannelFile.php';}$doc_channel = new PEAR_ChannelFile;$doc_channel->setServer('doc.php.net');$doc_channel->setAlias('phpdocs');$doc_channel->setSummary('PHP Documentation Team');$doc_channel->setDefaultPEARProtocols();$doc_channel->setBaseURL('REST1.0', 'http://doc.php.net/rest/');$doc_channel->setBaseURL('REST1.1', 'http://doc.php.net/rest/');$doc_channel->setBaseURL('REST1.3', 'http://doc.php.net/rest/');return $doc_channel;}if ($this->_getChannelFromAlias($channel) == '__uri') {// the registry is not properly set up, so use defaultsif (!class_exists('PEAR_ChannelFile')) {require_once 'PEAR/ChannelFile.php';}$private = new PEAR_ChannelFile;$private->setName('__uri');$private->setDefaultPEARProtocols();$private->setBaseURL('REST1.0', '****');$private->setSummary('Pseudo-channel for static packages');return $private;}return $ch;}/*** @param string Package name* @param string Channel name* @return bool*/function packageExists($package, $channel = 'pear.php.net'){if (PEAR::isError($e = $this->_lock(LOCK_SH))) {return $e;}$ret = $this->_packageExists($package, $channel);$this->_unlock();return $ret;}// }}}// {{{ channelExists()/*** @param string channel name* @param bool if true, then aliases will be ignored* @return bool*/function channelExists($channel, $noaliases = false){if (PEAR::isError($e = $this->_lock(LOCK_SH))) {return $e;}$ret = $this->_channelExists($channel, $noaliases);$this->_unlock();return $ret;}// }}}/*** @param string channel name mirror is in* @param string mirror name** @return bool*/function mirrorExists($channel, $mirror){if (PEAR::isError($e = $this->_lock(LOCK_SH))) {return $e;}$ret = $this->_mirrorExists($channel, $mirror);$this->_unlock();return $ret;}// {{{ isAlias()/*** Determines whether the parameter is an alias of a channel* @param string* @return bool*/function isAlias($alias){if (PEAR::isError($e = $this->_lock(LOCK_SH))) {return $e;}$ret = $this->_isChannelAlias($alias);$this->_unlock();return $ret;}// }}}// {{{ packageInfo()/*** @param string|null* @param string|null* @param string* @return array|null*/function packageInfo($package = null, $key = null, $channel = 'pear.php.net'){if (PEAR::isError($e = $this->_lock(LOCK_SH))) {return $e;}$ret = $this->_packageInfo($package, $key, $channel);$this->_unlock();return $ret;}// }}}// {{{ channelInfo()/*** Retrieve a raw array of channel data.** Do not use this, instead use {@link getChannel()} for normal* operations. Array structure is undefined in this method* @param string channel name* @param bool whether to strictly retrieve information only on non-aliases* @return array|null|PEAR_Error*/function channelInfo($channel = null, $noaliases = false){if (PEAR::isError($e = $this->_lock(LOCK_SH))) {return $e;}$ret = $this->_channelInfo($channel, $noaliases);$this->_unlock();return $ret;}// }}}/*** @param string*/function channelName($channel){if (PEAR::isError($e = $this->_lock(LOCK_SH))) {return $e;}$ret = $this->_getChannelFromAlias($channel);$this->_unlock();return $ret;}/*** @param string*/function channelAlias($channel){if (PEAR::isError($e = $this->_lock(LOCK_SH))) {return $e;}$ret = $this->_getAlias($channel);$this->_unlock();return $ret;}// {{{ listPackages()function listPackages($channel = false){if (PEAR::isError($e = $this->_lock(LOCK_SH))) {return $e;}$ret = $this->_listPackages($channel);$this->_unlock();return $ret;}// }}}// {{{ listAllPackages()function listAllPackages(){if (PEAR::isError($e = $this->_lock(LOCK_SH))) {return $e;}$ret = $this->_listAllPackages();$this->_unlock();return $ret;}// }}}// {{{ listChannel()function listChannels(){if (PEAR::isError($e = $this->_lock(LOCK_SH))) {return $e;}$ret = $this->_listChannels();$this->_unlock();return $ret;}// }}}// {{{ addPackage()/*** Add an installed package to the registry* @param string|PEAR_PackageFile_v1|PEAR_PackageFile_v2 package name or object* that will be passed to {@link addPackage2()}* @param array package info (parsed by PEAR_Common::infoFrom*() methods)* @return bool success of saving*/function addPackage($package, $info){if (is_object($info)) {return $this->addPackage2($info);}if (PEAR::isError($e = $this->_lock(LOCK_EX))) {return $e;}$ret = $this->_addPackage($package, $info);$this->_unlock();if ($ret) {if (!class_exists('PEAR_PackageFile_v1')) {require_once 'PEAR/PackageFile/v1.php';}$pf = new PEAR_PackageFile_v1;$pf->setConfig($this->_config);$pf->fromArray($info);$this->_dependencyDB->uninstallPackage($pf);$this->_dependencyDB->installPackage($pf);}return $ret;}// }}}// {{{ addPackage2()function addPackage2($info){if (!is_object($info)) {return $this->addPackage($info['package'], $info);}if (PEAR::isError($e = $this->_lock(LOCK_EX))) {return $e;}$ret = $this->_addPackage2($info);$this->_unlock();if ($ret) {$this->_dependencyDB->uninstallPackage($info);$this->_dependencyDB->installPackage($info);}return $ret;}// }}}// {{{ updateChannel()/*** For future expandibility purposes, separate this* @param PEAR_ChannelFile*/function updateChannel($channel, $lastmodified = null){if ($channel->getName() == '__uri') {return false;}return $this->addChannel($channel, $lastmodified, true);}// }}}// {{{ deleteChannel()/*** Deletion fails if there are any packages installed from the channel* @param string|PEAR_ChannelFile channel name* @return boolean|PEAR_Error True on deletion, false if it doesn't exist*/function deleteChannel($channel){if (PEAR::isError($e = $this->_lock(LOCK_EX))) {return $e;}$ret = $this->_deleteChannel($channel);$this->_unlock();if ($ret && is_a($this->_config, 'PEAR_Config')) {$this->_config->setChannels($this->listChannels());}return $ret;}// }}}// {{{ addChannel()/*** @param PEAR_ChannelFile Channel object* @param string Last-Modified header from HTTP for caching* @return boolean|PEAR_Error True on creation, false if it already exists*/function addChannel($channel, $lastmodified = false, $update = false){if (!is_a($channel, 'PEAR_ChannelFile') || !$channel->validate()) {return false;}if (PEAR::isError($e = $this->_lock(LOCK_EX))) {return $e;}$ret = $this->_addChannel($channel, $update, $lastmodified);$this->_unlock();if (!$update && $ret && is_a($this->_config, 'PEAR_Config')) {$this->_config->setChannels($this->listChannels());}return $ret;}// }}}// {{{ deletePackage()function deletePackage($package, $channel = 'pear.php.net'){if (PEAR::isError($e = $this->_lock(LOCK_EX))) {return $e;}$file = $this->_packageFileName($package, $channel);$ret = file_exists($file) ? @unlink($file) : false;$this->_rebuildFileMap();$this->_unlock();$p = array('channel' => $channel, 'package' => $package);$this->_dependencyDB->uninstallPackage($p);return $ret;}// }}}// {{{ updatePackage()function updatePackage($package, $info, $merge = true){if (is_object($info)) {return $this->updatePackage2($info, $merge);}if (PEAR::isError($e = $this->_lock(LOCK_EX))) {return $e;}$ret = $this->_updatePackage($package, $info, $merge);$this->_unlock();if ($ret) {if (!class_exists('PEAR_PackageFile_v1')) {require_once 'PEAR/PackageFile/v1.php';}$pf = new PEAR_PackageFile_v1;$pf->setConfig($this->_config);$pf->fromArray($this->packageInfo($package));$this->_dependencyDB->uninstallPackage($pf);$this->_dependencyDB->installPackage($pf);}return $ret;}// }}}// {{{ updatePackage2()function updatePackage2($info){if (!is_object($info)) {return $this->updatePackage($info['package'], $info, $merge);}if (!$info->validate(PEAR_VALIDATE_DOWNLOADING)) {return false;}if (PEAR::isError($e = $this->_lock(LOCK_EX))) {return $e;}$ret = $this->_updatePackage2($info);$this->_unlock();if ($ret) {$this->_dependencyDB->uninstallPackage($info);$this->_dependencyDB->installPackage($info);}return $ret;}// }}}// {{{ getChannel()/*** @param string channel name* @param bool whether to strictly return raw channels (no aliases)* @return PEAR_ChannelFile|PEAR_Error*/function getChannel($channel, $noaliases = false){if (PEAR::isError($e = $this->_lock(LOCK_SH))) {return $e;}$ret = $this->_getChannel($channel, $noaliases);$this->_unlock();if (!$ret) {return PEAR::raiseError('Unknown channel: ' . $channel);}return $ret;}// }}}// {{{ getPackage()/*** @param string package name* @param string channel name* @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|null*/function &getPackage($package, $channel = 'pear.php.net'){if (PEAR::isError($e = $this->_lock(LOCK_SH))) {return $e;}$pf = &$this->_getPackage($package, $channel);$this->_unlock();return $pf;}// }}}/*** Get PEAR_PackageFile_v[1/2] objects representing the contents of* a dependency group that are installed.** This is used at uninstall-time* @param array* @return array|false*/function getInstalledGroup($group){$ret = array();if (isset($group['package'])) {if (!isset($group['package'][0])) {$group['package'] = array($group['package']);}foreach ($group['package'] as $package) {$depchannel = isset($package['channel']) ? $package['channel'] : '__uri';$p = &$this->getPackage($package['name'], $depchannel);if ($p) {$save = &$p;$ret[] = &$save;}}}if (isset($group['subpackage'])) {if (!isset($group['subpackage'][0])) {$group['subpackage'] = array($group['subpackage']);}foreach ($group['subpackage'] as $package) {$depchannel = isset($package['channel']) ? $package['channel'] : '__uri';$p = &$this->getPackage($package['name'], $depchannel);if ($p) {$save = &$p;$ret[] = &$save;}}}if (!count($ret)) {return false;}return $ret;}// {{{ getChannelValidator()/*** @param string channel name* @return PEAR_Validate|false*/function &getChannelValidator($channel){$chan = $this->getChannel($channel);if (PEAR::isError($chan)) {return $chan;}$val = $chan->getValidationObject();return $val;}// }}}// {{{ getChannels()/*** @param string channel name* @return array an array of PEAR_ChannelFile objects representing every installed channel*/function &getChannels(){$ret = array();if (PEAR::isError($e = $this->_lock(LOCK_SH))) {return $e;}foreach ($this->_listChannels() as $channel) {$e = &$this->_getChannel($channel);if (!$e || PEAR::isError($e)) {continue;}$ret[] = $e;}$this->_unlock();return $ret;}// }}}// {{{ checkFileMap()/*** Test whether a file or set of files belongs to a package.** If an array is passed in* @param string|array file path, absolute or relative to the pear* install dir* @param string|array name of PEAR package or array('package' => name, 'channel' =>* channel) of a package that will be ignored* @param string API version - 1.1 will exclude any files belonging to a package* @param array private recursion variable* @return array|false which package and channel the file belongs to, or an empty* string if the file does not belong to an installed package,* or belongs to the second parameter's package*/function checkFileMap($path, $package = false, $api = '1.0', $attrs = false){if (is_array($path)) {static $notempty;if (empty($notempty)) {if (!class_exists('PEAR_Installer_Role')) {require_once 'PEAR/Installer/Role.php';}$notempty = create_function('$a','return !empty($a);');}$package = is_array($package) ? array(strtolower($package[0]), strtolower($package[1])): strtolower($package);$pkgs = array();foreach ($path as $name => $attrs) {if (is_array($attrs)) {if (isset($attrs['install-as'])) {$name = $attrs['install-as'];}if (!in_array($attrs['role'], PEAR_Installer_Role::getInstallableRoles())) {// these are not installedcontinue;}if (!in_array($attrs['role'], PEAR_Installer_Role::getBaseinstallRoles())) {$attrs['baseinstalldir'] = is_array($package) ? $package[1] : $package;}if (isset($attrs['baseinstalldir'])) {$name = $attrs['baseinstalldir'] . DIRECTORY_SEPARATOR . $name;}}$pkgs[$name] = $this->checkFileMap($name, $package, $api, $attrs);if (PEAR::isError($pkgs[$name])) {return $pkgs[$name];}}return array_filter($pkgs, $notempty);}if (empty($this->filemap_cache)) {if (PEAR::isError($e = $this->_lock(LOCK_SH))) {return $e;}$err = $this->_readFileMap();$this->_unlock();if (PEAR::isError($err)) {return $err;}}if (!$attrs) {$attrs = array('role' => 'php'); // any old call would be for PHP role only}if (isset($this->filemap_cache[$attrs['role']][$path])) {if ($api >= '1.1' && $this->filemap_cache[$attrs['role']][$path] == $package) {return false;}return $this->filemap_cache[$attrs['role']][$path];}$l = strlen($this->install_dir);if (substr($path, 0, $l) == $this->install_dir) {$path = preg_replace('!^'.DIRECTORY_SEPARATOR.'+!', '', substr($path, $l));}if (isset($this->filemap_cache[$attrs['role']][$path])) {if ($api >= '1.1' && $this->filemap_cache[$attrs['role']][$path] == $package) {return false;}return $this->filemap_cache[$attrs['role']][$path];}return false;}// }}}// {{{ flush()/*** Force a reload of the filemap* @since 1.5.0RC3*/function flushFileMap(){$this->filemap_cache = null;clearstatcache(); // ensure that the next read gets the full, current filemap}// }}}// {{{ apiVersion()/*** Get the expected API version. Channels API is version 1.1, as it is backwards* compatible with 1.0* @return string*/function apiVersion(){return '1.1';}// }}}/*** Parse a package name, or validate a parsed package name array* @param string|array pass in an array of format* array(* 'package' => 'pname',* ['channel' => 'channame',]* ['version' => 'version',]* ['state' => 'state',]* ['group' => 'groupname'])* or a string of format* [channel://][channame/]pname[-version|-state][/group=groupname]* @return array|PEAR_Error*/function parsePackageName($param, $defaultchannel = 'pear.php.net'){$saveparam = $param;if (is_array($param)) {// convert to string for error messages$saveparam = $this->parsedPackageNameToString($param);// process the arrayif (!isset($param['package'])) {return PEAR::raiseError('parsePackageName(): array $param ' .'must contain a valid package name in index "param"','package', null, null, $param);}if (!isset($param['uri'])) {if (!isset($param['channel'])) {$param['channel'] = $defaultchannel;}} else {$param['channel'] = '__uri';}} else {$components = @parse_url((string) $param);if (isset($components['scheme'])) {if ($components['scheme'] == 'http') {// uri package$param = array('uri' => $param, 'channel' => '__uri');} elseif($components['scheme'] != 'channel') {return PEAR::raiseError('parsePackageName(): only channel:// uris may ' .'be downloaded, not "' . $param . '"', 'invalid', null, null, $param);}}if (!isset($components['path'])) {return PEAR::raiseError('parsePackageName(): array $param ' .'must contain a valid package name in "' . $param . '"','package', null, null, $param);}if (isset($components['host'])) {// remove the leading "/"$components['path'] = substr($components['path'], 1);}if (!isset($components['scheme'])) {if (strpos($components['path'], '/') !== false) {if ($components['path']{0} == '/') {return PEAR::raiseError('parsePackageName(): this is not ' .'a package name, it begins with "/" in "' . $param . '"','invalid', null, null, $param);}$parts = explode('/', $components['path']);$components['host'] = array_shift($parts);if (count($parts) > 1) {$components['path'] = array_pop($parts);$components['host'] .= '/' . implode('/', $parts);} else {$components['path'] = implode('/', $parts);}} else {$components['host'] = $defaultchannel;}} else {if (strpos($components['path'], '/')) {$parts = explode('/', $components['path']);$components['path'] = array_pop($parts);$components['host'] .= '/' . implode('/', $parts);}}if (is_array($param)) {$param['package'] = $components['path'];} else {$param = array('package' => $components['path']);if (isset($components['host'])) {$param['channel'] = $components['host'];}}if (isset($components['fragment'])) {$param['group'] = $components['fragment'];}if (isset($components['user'])) {$param['user'] = $components['user'];}if (isset($components['pass'])) {$param['pass'] = $components['pass'];}if (isset($components['query'])) {parse_str($components['query'], $param['opts']);}// check for extension$pathinfo = pathinfo($param['package']);if (isset($pathinfo['extension']) &&in_array(strtolower($pathinfo['extension']), array('tgz', 'tar'))) {$param['extension'] = $pathinfo['extension'];$param['package'] = substr($pathinfo['basename'], 0,strlen($pathinfo['basename']) - 4);}// check for versionif (strpos($param['package'], '-')) {$test = explode('-', $param['package']);if (count($test) != 2) {return PEAR::raiseError('parsePackageName(): only one version/state ' .'delimiter "-" is allowed in "' . $saveparam . '"','version', null, null, $param);}list($param['package'], $param['version']) = $test;}}// validation$info = $this->channelExists($param['channel']);if (PEAR::isError($info)) {return $info;}if (!$info) {return PEAR::raiseError('unknown channel "' . $param['channel'] .'" in "' . $saveparam . '"', 'channel', null, null, $param);}$chan = $this->getChannel($param['channel']);if (PEAR::isError($chan)) {return $chan;}if (!$chan) {return PEAR::raiseError("Exception: corrupt registry, could not " ."retrieve channel " . $param['channel'] . " information",'registry', null, null, $param);}$param['channel'] = $chan->getName();$validate = $chan->getValidationObject();$vpackage = $chan->getValidationPackage();// validate package nameif (!$validate->validPackageName($param['package'], $vpackage['_content'])) {return PEAR::raiseError('parsePackageName(): invalid package name "' .$param['package'] . '" in "' . $saveparam . '"','package', null, null, $param);}if (isset($param['group'])) {if (!PEAR_Validate::validGroupName($param['group'])) {return PEAR::raiseError('parsePackageName(): dependency group "' . $param['group'] .'" is not a valid group name in "' . $saveparam . '"', 'group', null, null,$param);}}if (isset($param['state'])) {if (!in_array(strtolower($param['state']), $validate->getValidStates())) {return PEAR::raiseError('parsePackageName(): state "' . $param['state']. '" is not a valid state in "' . $saveparam . '"','state', null, null, $param);}}if (isset($param['version'])) {if (isset($param['state'])) {return PEAR::raiseError('parsePackageName(): cannot contain both ' .'a version and a stability (state) in "' . $saveparam . '"','version/state', null, null, $param);}// check whether version is actually a stateif (in_array(strtolower($param['version']), $validate->getValidStates())) {$param['state'] = strtolower($param['version']);unset($param['version']);} else {if (!$validate->validVersion($param['version'])) {return PEAR::raiseError('parsePackageName(): "' . $param['version'] .'" is neither a valid version nor a valid state in "' .$saveparam . '"', 'version/state', null, null, $param);}}}return $param;}/*** @param array* @return string*/function parsedPackageNameToString($parsed, $brief = false){if (is_string($parsed)) {return $parsed;}if (is_object($parsed)) {$p = $parsed;$parsed = array('package' => $p->getPackage(),'channel' => $p->getChannel(),'version' => $p->getVersion(),);}if (isset($parsed['uri'])) {return $parsed['uri'];}if ($brief) {if ($channel = $this->channelAlias($parsed['channel'])) {return $channel . '/' . $parsed['package'];}}$upass = '';if (isset($parsed['user'])) {$upass = $parsed['user'];if (isset($parsed['pass'])) {$upass .= ':' . $parsed['pass'];}$upass = "$upass@";}$ret = 'channel://' . $upass . $parsed['channel'] . '/' . $parsed['package'];if (isset($parsed['version']) || isset($parsed['state'])) {$ver = isset($parsed['version']) ? $parsed['version'] : '';$ver .= isset($parsed['state']) ? $parsed['state'] : '';$ret .= '-' . $ver;}if (isset($parsed['extension'])) {$ret .= '.' . $parsed['extension'];}if (isset($parsed['opts'])) {$ret .= '?';foreach ($parsed['opts'] as $name => $value) {$parsed['opts'][$name] = "$name=$value";}$ret .= implode('&', $parsed['opts']);}if (isset($parsed['group'])) {$ret .= '#' . $parsed['group'];}return $ret;}}