Вход Регистрация
Файл: mp3/MP3/PEAR/Registry.php
Строк: 2834
<?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
 * @version    CVS: $Id: Registry.php 313023 2011-07-06 19:17:11Z dufuz $
 * @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.9.4
 * @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 PEAR_Registry($pear_install_dir = PEAR_INSTALL_DIR, $pear_channel = false,
                           
$pecl_channel = false)
    {
        
parent::PEAR();
        
$this->setInstallDir($pear_install_dir);
        
$this->_pearChannel = $pear_channel;
        
$this->_peclChannel = $pecl_channel;
        
$this->_config      = false;
    }

    function 
setInstallDir($pear_install_dir = PEAR_INSTALL_DIR)
    {
        
$ds = DIRECTORY_SEPARATOR;
        
$this->install_dir = $pear_install_dir;
        
$this->channelsdir = $pear_install_dir.$ds.'.channels';
        
$this->statedir    = $pear_install_dir.$ds.'.registry';
        
$this->filemap     = $pear_install_dir.$ds.'.filemap';
        
$this->lockfile    = $pear_install_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 mode
                    
return @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'));
        }
    }

    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 lowercase
        
if (!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 db
                    
if (file_exists($this->_config->get('php_dir', null, 'pear.php.net') .
                        
DIRECTORY_SEPARATOR . '.depdb')) {
                        @
unlink($this->_config->get('php_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 channel
            
return 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 files
                    
if ($name == 'dirtree') {
                        continue;
                    }

                    if (isset(
$attrs['role']) && !in_array($attrs['role'],
                          
PEAR_Installer_Role::getInstallableRoles())) {
                        
// these are not installed
                        
continue;
                    }

                    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();
        
$rt = get_magic_quotes_runtime();
        
set_magic_quotes_runtime(0);
        
$fsize = filesize($this->filemap);
        
fclose($fp);
        
$data = file_get_contents($this->filemap);
        
set_magic_quotes_runtime($rt);
        
$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;
        }

        
$rt = get_magic_quotes_runtime();
        
set_magic_quotes_runtime(0);
        
clearstatcache();
        
$this->_closePackageFile($fp);
        
$data = file_get_contents($this->_packageFileName($package, $channel));
        
set_magic_quotes_runtime($rt);
        
$data = unserialize($data);
        if (
$key === null) {
            return 
$data;
        }

        
// compatibility for package.xml version 2.0
        
if (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;
        }

        
$rt = get_magic_quotes_runtime();
        
set_magic_quotes_runtime(0);
        
clearstatcache();
        
$this->_closeChannelFile($fp);
        
$data = file_get_contents($this->_channelFileName($channel));
        
set_magic_quotes_runtime($rt);
        
$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 defaults
            
if (!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 defaults
            
if (!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 defaults
            
if (!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 defaults
            
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');
            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 installed
                        
continue;
                    }
                    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 array
            
if (!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 version
            
if (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 name
        
if (!$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 state
            
if (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;
    }
}
Онлайн: 0
Реклама