PEAR
[ class tree: PEAR ] [ index: PEAR ] [ all elements ]

Source for file Registry.php

Documentation is available at Registry.php

  1. <?php
  2. /**
  3.  * PEAR_Registry
  4.  *
  5.  * PHP versions 4 and 5
  6.  *
  7.  * @category   pear
  8.  * @package    PEAR
  9.  * @author     Stig Bakken <ssb@php.net>
  10.  * @author     Tomas V. V. Cox <cox@idecnet.com>
  11.  * @author     Greg Beaver <cellog@php.net>
  12.  * @copyright  1997-2009 The Authors
  13.  * @license    http://opensource.org/licenses/bsd-license.php New BSD License
  14.  * @version    CVS: $Id: Registry.php 313023 2011-07-06 19:17:11Z dufuz $
  15.  * @link       http://pear.php.net/package/PEAR
  16.  * @since      File available since Release 0.1
  17.  */
  18.  
  19. /**
  20.  * for PEAR_Error
  21.  */
  22. require_once 'PEAR.php';
  23. require_once 'PEAR/DependencyDB.php';
  24.  
  25. define('PEAR_REGISTRY_ERROR_LOCK',         -2);
  26. define('PEAR_REGISTRY_ERROR_FORMAT',       -3);
  27. define('PEAR_REGISTRY_ERROR_FILE',         -4);
  28. define('PEAR_REGISTRY_ERROR_CONFLICT',     -5);
  29. define('PEAR_REGISTRY_ERROR_CHANNEL_FILE'-6);
  30.  
  31. /**
  32.  * Administration class used to maintain the installed package database.
  33.  * @category   pear
  34.  * @package    PEAR
  35.  * @author     Stig Bakken <ssb@php.net>
  36.  * @author     Tomas V. V. Cox <cox@idecnet.com>
  37.  * @author     Greg Beaver <cellog@php.net>
  38.  * @copyright  1997-2009 The Authors
  39.  * @license    http://opensource.org/licenses/bsd-license.php New BSD License
  40.  * @version    Release: 1.9.4
  41.  * @link       http://pear.php.net/package/PEAR
  42.  * @since      Class available since Release 1.4.0a1
  43.  */
  44. class PEAR_Registry extends PEAR
  45. {
  46.     /**
  47.      * File containing all channel information.
  48.      * @var string 
  49.      */
  50.     var $channels = '';
  51.  
  52.     /** Directory where registry files are stored.
  53.      * @var string 
  54.      */
  55.     var $statedir = '';
  56.  
  57.     /** File where the file map is stored
  58.      * @var string 
  59.      */
  60.     var $filemap = '';
  61.  
  62.     /** Directory where registry files for channels are stored.
  63.      * @var string 
  64.      */
  65.     var $channelsdir = '';
  66.  
  67.     /** Name of file used for locking the registry
  68.      * @var string 
  69.      */
  70.     var $lockfile = '';
  71.  
  72.     /** File descriptor used during locking
  73.      * @var resource 
  74.      */
  75.     var $lock_fp = null;
  76.  
  77.     /** Mode used during locking
  78.      * @var int 
  79.      */
  80.     var $lock_mode = 0; // XXX UNUSED
  81.  
  82.     /** Cache of package information.  Structure:
  83.      * array(
  84.      *   'package' => array('id' => ... ),
  85.      *   ... )
  86.      * @var array 
  87.      */
  88.     var $pkginfo_cache = array();
  89.  
  90.     /** Cache of file map.  Structure:
  91.      * array( '/path/to/file' => 'package', ... )
  92.      * @var array 
  93.      */
  94.     var $filemap_cache = array();
  95.  
  96.     /**
  97.      * @var false|PEAR_ChannelFile
  98.      */
  99.     var $_pearChannel;
  100.  
  101.     /**
  102.      * @var false|PEAR_ChannelFile
  103.      */
  104.     var $_peclChannel;
  105.  
  106.     /**
  107.      * @var false|PEAR_ChannelFile
  108.      */
  109.     var $_docChannel;
  110.  
  111.     /**
  112.      * @var PEAR_DependencyDB 
  113.      */
  114.     var $_dependencyDB;
  115.  
  116.     /**
  117.      * @var PEAR_Config 
  118.      */
  119.     var $_config;
  120.  
  121.     /**
  122.      * PEAR_Registry constructor.
  123.      *
  124.      * @param string (optional) PEAR install directory (for .php files)
  125.      * @param PEAR_ChannelFile PEAR_ChannelFile object representing the PEAR channel, if
  126.      *         default values are not desired.  Only used the very first time a PEAR
  127.      *         repository is initialized
  128.      * @param PEAR_ChannelFile PEAR_ChannelFile object representing the PECL channel, if
  129.      *         default values are not desired.  Only used the very first time a PEAR
  130.      *         repository is initialized
  131.      *
  132.      * @access public
  133.      */
  134.     function PEAR_Registry($pear_install_dir = PEAR_INSTALL_DIR$pear_channel = false,
  135.                            $pecl_channel = false)
  136.     {
  137.         parent::PEAR();
  138.         $this->setInstallDir($pear_install_dir);
  139.         $this->_pearChannel $pear_channel;
  140.         $this->_peclChannel $pecl_channel;
  141.         $this->_config      = false;
  142.     }
  143.  
  144.     function setInstallDir($pear_install_dir = PEAR_INSTALL_DIR)
  145.     {
  146.         $ds = DIRECTORY_SEPARATOR;
  147.         $this->install_dir $pear_install_dir;
  148.         $this->channelsdir = $pear_install_dir.$ds.'.channels';
  149.         $this->statedir    = $pear_install_dir.$ds.'.registry';
  150.         $this->filemap     = $pear_install_dir.$ds.'.filemap';
  151.         $this->lockfile    = $pear_install_dir.$ds.'.lock';
  152.     }
  153.  
  154.     function hasWriteAccess()
  155.     {
  156.         if (!file_exists($this->install_dir)) {
  157.             $dir $this->install_dir;
  158.             while ($dir && $dir != '.'{
  159.                 $olddir $dir;
  160.                 $dir    dirname($dir);
  161.                 if ($dir != '.' && file_exists($dir)) {
  162.                     if (is_writeable($dir)) {
  163.                         return true;
  164.                     }
  165.  
  166.                     return false;
  167.                 }
  168.  
  169.                 if ($dir == $olddir// this can happen in safe mode
  170.                     return @is_writable($dir);
  171.                 }
  172.             }
  173.  
  174.             return false;
  175.         }
  176.  
  177.         return is_writeable($this->install_dir);
  178.     }
  179.  
  180.     function setConfig(&$config$resetInstallDir = true)
  181.     {
  182.         $this->_config &$config;
  183.         if ($resetInstallDir{
  184.             $this->setInstallDir($config->get('php_dir'));
  185.         }
  186.     }
  187.  
  188.     function _initializeChannelDirs()
  189.     {
  190.         static $running = false;
  191.         if (!$running{
  192.             $running = true;
  193.             $ds = DIRECTORY_SEPARATOR;
  194.             if (!is_dir($this->channelsdir||
  195.                   !file_exists($this->channelsdir . $ds 'pear.php.net.reg'||
  196.                   !file_exists($this->channelsdir . $ds 'pecl.php.net.reg'||
  197.                   !file_exists($this->channelsdir . $ds 'doc.php.net.reg'||
  198.                   !file_exists($this->channelsdir . $ds '__uri.reg')) {
  199.                 if (!file_exists($this->channelsdir . $ds 'pear.php.net.reg')) {
  200.                     $pear_channel $this->_pearChannel;
  201.                     if (!is_a($pear_channel'PEAR_ChannelFile'|| !$pear_channel->validate()) {
  202.                         if (!class_exists('PEAR_ChannelFile')) {
  203.                             require_once 'PEAR/ChannelFile.php';
  204.                         }
  205.  
  206.                         $pear_channel = new PEAR_ChannelFile;
  207.                         $pear_channel->setAlias('pear');
  208.                         $pear_channel->setServer('pear.php.net');
  209.                         $pear_channel->setSummary('PHP Extension and Application Repository');
  210.                         $pear_channel->setDefaultPEARProtocols();
  211.                         $pear_channel->setBaseURL('REST1.0''http://pear.php.net/rest/');
  212.                         $pear_channel->setBaseURL('REST1.1''http://pear.php.net/rest/');
  213.                         $pear_channel->setBaseURL('REST1.3''http://pear.php.net/rest/');
  214.                         //$pear_channel->setBaseURL('REST1.4', 'http://pear.php.net/rest/');
  215.                     else {
  216.                         $pear_channel->setServer('pear.php.net');
  217.                         $pear_channel->setAlias('pear');
  218.                     }
  219.  
  220.                     $pear_channel->validate();
  221.                     $this->_addChannel($pear_channel);
  222.                 }
  223.  
  224.                 if (!file_exists($this->channelsdir . $ds 'pecl.php.net.reg')) {
  225.                     $pecl_channel $this->_peclChannel;
  226.                     if (!is_a($pecl_channel'PEAR_ChannelFile'|| !$pecl_channel->validate()) {
  227.                         if (!class_exists('PEAR_ChannelFile')) {
  228.                             require_once 'PEAR/ChannelFile.php';
  229.                         }
  230.  
  231.                         $pecl_channel = new PEAR_ChannelFile;
  232.                         $pecl_channel->setAlias('pecl');
  233.                         $pecl_channel->setServer('pecl.php.net');
  234.                         $pecl_channel->setSummary('PHP Extension Community Library');
  235.                         $pecl_channel->setDefaultPEARProtocols();
  236.                         $pecl_channel->setBaseURL('REST1.0''http://pecl.php.net/rest/');
  237.                         $pecl_channel->setBaseURL('REST1.1''http://pecl.php.net/rest/');
  238.                         $pecl_channel->setValidationPackage('PEAR_Validator_PECL''1.0');
  239.                     else {
  240.                         $pecl_channel->setServer('pecl.php.net');
  241.                         $pecl_channel->setAlias('pecl');
  242.                     }
  243.  
  244.                     $pecl_channel->validate();
  245.                     $this->_addChannel($pecl_channel);
  246.                 }
  247.  
  248.                 if (!file_exists($this->channelsdir . $ds 'doc.php.net.reg')) {
  249.                     $doc_channel $this->_docChannel;
  250.                     if (!is_a($doc_channel'PEAR_ChannelFile'|| !$doc_channel->validate()) {
  251.                         if (!class_exists('PEAR_ChannelFile')) {
  252.                             require_once 'PEAR/ChannelFile.php';
  253.                         }
  254.  
  255.                         $doc_channel = new PEAR_ChannelFile;
  256.                         $doc_channel->setAlias('phpdocs');
  257.                         $doc_channel->setServer('doc.php.net');
  258.                         $doc_channel->setSummary('PHP Documentation Team');
  259.                         $doc_channel->setDefaultPEARProtocols();
  260.                         $doc_channel->setBaseURL('REST1.0''http://doc.php.net/rest/');
  261.                         $doc_channel->setBaseURL('REST1.1''http://doc.php.net/rest/');
  262.                         $doc_channel->setBaseURL('REST1.3''http://doc.php.net/rest/');
  263.                     else {
  264.                         $doc_channel->setServer('doc.php.net');
  265.                         $doc_channel->setAlias('doc');
  266.                     }
  267.  
  268.                     $doc_channel->validate();
  269.                     $this->_addChannel($doc_channel);
  270.                 }
  271.  
  272.                 if (!file_exists($this->channelsdir . $ds '__uri.reg')) {
  273.                     if (!class_exists('PEAR_ChannelFile')) {
  274.                         require_once 'PEAR/ChannelFile.php';
  275.                     }
  276.  
  277.                     $private = new PEAR_ChannelFile;
  278.                     $private->setName('__uri');
  279.                     $private->setDefaultPEARProtocols();
  280.                     $private->setBaseURL('REST1.0''****');
  281.                     $private->setSummary('Pseudo-channel for static packages');
  282.                     $this->_addChannel($private);
  283.                 }
  284.                 $this->_rebuildFileMap();
  285.             }
  286.  
  287.             $running = false;
  288.         }
  289.     }
  290.  
  291.     function _initializeDirs()
  292.     {
  293.         $ds = DIRECTORY_SEPARATOR;
  294.         // XXX Compatibility code should be removed in the future
  295.         // rename all registry files if any to lowercase
  296.         if (!OS_WINDOWS && file_exists($this->statedir&& is_dir($this->statedir&&
  297.               $handle opendir($this->statedir)) {
  298.             $dest $this->statedir . $ds;
  299.             while (false !== ($file readdir($handle))) {
  300.                 if (preg_match('/^.*[A-Z].*\.reg\\z/'$file)) {
  301.                     rename($dest $file$dest strtolower($file));
  302.                 }
  303.             }
  304.             closedir($handle);
  305.         }
  306.  
  307.         $this->_initializeChannelDirs();
  308.         if (!file_exists($this->filemap)) {
  309.             $this->_rebuildFileMap();
  310.         }
  311.         $this->_initializeDepDB();
  312.     }
  313.  
  314.     function _initializeDepDB()
  315.     {
  316.         if (!isset($this->_dependencyDB)) {
  317.             static $initializing = false;
  318.             if (!$initializing{
  319.                 $initializing = true;
  320.                 if (!$this->_config// never used?
  321.                     $file = OS_WINDOWS ? 'pear.ini' '.pearrc';
  322.                     $this->_config = &new PEAR_Config($this->statedir . DIRECTORY_SEPARATOR .
  323.                         $file);
  324.                     $this->_config->setRegistry($this);
  325.                     $this->_config->set('php_dir'$this->install_dir);
  326.                 }
  327.  
  328.                 $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->_config);
  329.                 if (PEAR::isError($this->_dependencyDB)) {
  330.                     // attempt to recover by removing the dep db
  331.                     if (file_exists($this->_config->get('php_dir'null'pear.php.net'.
  332.                         DIRECTORY_SEPARATOR . '.depdb')) {
  333.                         @unlink($this->_config->get('php_dir'null'pear.php.net'.
  334.                             DIRECTORY_SEPARATOR . '.depdb');
  335.                     }
  336.  
  337.                     $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->_config);
  338.                     if (PEAR::isError($this->_dependencyDB)) {
  339.                         echo $this->_dependencyDB->getMessage();
  340.                         echo 'Unrecoverable error';
  341.                         exit(1);
  342.                     }
  343.                 }
  344.  
  345.                 $initializing = false;
  346.             }
  347.         }
  348.     }
  349.  
  350.     /**
  351.      * PEAR_Registry destructor.  Makes sure no locks are forgotten.
  352.      *
  353.      * @access private
  354.      */
  355.     function _PEAR_Registry()
  356.     {
  357.         parent::_PEAR();
  358.         if (is_resource($this->lock_fp)) {
  359.             $this->_unlock();
  360.         }
  361.     }
  362.  
  363.     /**
  364.      * Make sure the directory where we keep registry files exists.
  365.      *
  366.      * @return bool TRUE if directory exists, FALSE if it could not be
  367.      *  created
  368.      *
  369.      * @access private
  370.      */
  371.     function _assertStateDir($channel = false)
  372.     {
  373.         if ($channel && $this->_getChannelFromAlias($channel!= 'pear.php.net'{
  374.             return $this->_assertChannelStateDir($channel);
  375.         }
  376.  
  377.         static $init = false;
  378.         if (!file_exists($this->statedir)) {
  379.             if (!$this->hasWriteAccess()) {
  380.                 return false;
  381.             }
  382.  
  383.             require_once 'System.php';
  384.             if (!System::mkdir(array('-p'$this->statedir))) {
  385.                 return $this->raiseError("could not create directory '{$this->statedir}'");
  386.             }
  387.             $init = true;
  388.         elseif (!is_dir($this->statedir)) {
  389.             return $this->raiseError('Cannot create directory ' $this->statedir . ', ' .
  390.                 'it already exists and is not a directory');
  391.         }
  392.  
  393.         $ds = DIRECTORY_SEPARATOR;
  394.         if (!file_exists($this->channelsdir)) {
  395.             if (!file_exists($this->channelsdir . $ds 'pear.php.net.reg'||
  396.                   !file_exists($this->channelsdir . $ds 'pecl.php.net.reg'||
  397.                   !file_exists($this->channelsdir . $ds 'doc.php.net.reg'||
  398.                   !file_exists($this->channelsdir . $ds '__uri.reg')) {
  399.                 $init = true;
  400.             }
  401.         elseif (!is_dir($this->channelsdir)) {
  402.             return $this->raiseError('Cannot create directory ' $this->channelsdir . ', ' .
  403.                 'it already exists and is not a directory');
  404.         }
  405.  
  406.         if ($init{
  407.             static $running = false;
  408.             if (!$running{
  409.                 $running = true;
  410.                 $this->_initializeDirs();
  411.                 $running = false;
  412.                 $init = false;
  413.             }
  414.         else {
  415.             $this->_initializeDepDB();
  416.         }
  417.  
  418.         return true;
  419.     }
  420.  
  421.     /**
  422.      * Make sure the directory where we keep registry files exists for a non-standard channel.
  423.      *
  424.      * @param string channel name
  425.      * @return bool TRUE if directory exists, FALSE if it could not be
  426.      *  created
  427.      *
  428.      * @access private
  429.      */
  430.     function _assertChannelStateDir($channel)
  431.     {
  432.         $ds = DIRECTORY_SEPARATOR;
  433.         if (!$channel || $this->_getChannelFromAlias($channel== 'pear.php.net'{
  434.             if (!file_exists($this->channelsdir . $ds 'pear.php.net.reg')) {
  435.                 $this->_initializeChannelDirs();
  436.             }
  437.             return $this->_assertStateDir($channel);
  438.         }
  439.  
  440.         $channelDir $this->_channelDirectoryName($channel);
  441.         if (!is_dir($this->channelsdir||
  442.               !file_exists($this->channelsdir . $ds 'pear.php.net.reg')) {
  443.             $this->_initializeChannelDirs();
  444.         }
  445.  
  446.         if (!file_exists($channelDir)) {
  447.             if (!$this->hasWriteAccess()) {
  448.                 return false;
  449.             }
  450.  
  451.             require_once 'System.php';
  452.             if (!System::mkdir(array('-p'$channelDir))) {
  453.                 return $this->raiseError("could not create directory '" $channelDir .
  454.                     "'");
  455.             }
  456.         elseif (!is_dir($channelDir)) {
  457.             return $this->raiseError("could not create directory '" $channelDir .
  458.                 "', already exists and is not a directory");
  459.         }
  460.  
  461.         return true;
  462.     }
  463.  
  464.     /**
  465.      * Make sure the directory where we keep registry files for channels exists
  466.      *
  467.      * @return bool TRUE if directory exists, FALSE if it could not be
  468.      *  created
  469.      *
  470.      * @access private
  471.      */
  472.     function _assertChannelDir()
  473.     {
  474.         if (!file_exists($this->channelsdir)) {
  475.             if (!$this->hasWriteAccess()) {
  476.                 return false;
  477.             }
  478.  
  479.             require_once 'System.php';
  480.             if (!System::mkdir(array('-p'$this->channelsdir))) {
  481.                 return $this->raiseError("could not create directory '{$this->channelsdir}'");
  482.             }
  483.         elseif (!is_dir($this->channelsdir)) {
  484.             return $this->raiseError("could not create directory '{$this->channelsdir}" .
  485.                 "', it already exists and is not a directory");
  486.         }
  487.  
  488.         if (!file_exists($this->channelsdir . DIRECTORY_SEPARATOR . '.alias')) {
  489.             if (!$this->hasWriteAccess()) {
  490.                 return false;
  491.             }
  492.  
  493.             require_once 'System.php';
  494.             if (!System::mkdir(array('-p'$this->channelsdir . DIRECTORY_SEPARATOR . '.alias'))) {
  495.                 return $this->raiseError("could not create directory '{$this->channelsdir}/.alias'");
  496.             }
  497.         elseif (!is_dir($this->channelsdir . DIRECTORY_SEPARATOR . '.alias')) {
  498.             return $this->raiseError("could not create directory '{$this->channelsdir}" .
  499.                 "/.alias', it already exists and is not a directory");
  500.         }
  501.  
  502.         return true;
  503.     }
  504.  
  505.     /**
  506.      * Get the name of the file where data for a given package is stored.
  507.      *
  508.      * @param string channel name, or false if this is a PEAR package
  509.      * @param string package name
  510.      *
  511.      * @return string registry file name
  512.      *
  513.      * @access public
  514.      */
  515.     function _packageFileName($package$channel = false)
  516.     {
  517.         if ($channel && $this->_getChannelFromAlias($channel!= 'pear.php.net'{
  518.             return $this->_channelDirectoryName($channel. DIRECTORY_SEPARATOR .
  519.                 strtolower($package'.reg';
  520.         }
  521.  
  522.         return $this->statedir . DIRECTORY_SEPARATOR . strtolower($package'.reg';
  523.     }
  524.  
  525.     /**
  526.      * Get the name of the file where data for a given channel is stored.
  527.      * @param string channel name
  528.      * @return string registry file name
  529.      */
  530.     function _channelFileName($channel$noaliases = false)
  531.     {
  532.         if (!$noaliases{
  533.             if (file_exists($this->_getChannelAliasFileName($channel))) {
  534.                 $channel implode(''file($this->_getChannelAliasFileName($channel)));
  535.             }
  536.         }
  537.         return $this->channelsdir . DIRECTORY_SEPARATOR . str_replace('/''_',
  538.             strtolower($channel)) '.reg';
  539.     }
  540.  
  541.     /**
  542.      * @param string 
  543.      * @return string 
  544.      */
  545.     function _getChannelAliasFileName($alias)
  546.     {
  547.         return $this->channelsdir . DIRECTORY_SEPARATOR . '.alias' .
  548.               DIRECTORY_SEPARATOR . str_replace('/''_'strtolower($alias)) '.txt';
  549.     }
  550.  
  551.     /**
  552.      * Get the name of a channel from its alias
  553.      */
  554.     function _getChannelFromAlias($channel)
  555.     {
  556.         if (!$this->_channelExists($channel)) {
  557.             if ($channel == 'pear.php.net'{
  558.                 return 'pear.php.net';
  559.             }
  560.  
  561.             if ($channel == 'pecl.php.net'{
  562.                 return 'pecl.php.net';
  563.             }
  564.  
  565.             if ($channel == 'doc.php.net'{
  566.                 return 'doc.php.net';
  567.             }
  568.  
  569.             if ($channel == '__uri'{
  570.                 return '__uri';
  571.             }
  572.  
  573.             return false;
  574.         }
  575.  
  576.         $channel strtolower($channel);
  577.         if (file_exists($this->_getChannelAliasFileName($channel))) {
  578.             // translate an alias to an actual channel
  579.             return implode(''file($this->_getChannelAliasFileName($channel)));
  580.         }
  581.  
  582.         return $channel;
  583.     }
  584.  
  585.     /**
  586.      * Get the alias of a channel from its alias or its name
  587.      */
  588.     function _getAlias($channel)
  589.     {
  590.         if (!$this->_channelExists($channel)) {
  591.             if ($channel == 'pear.php.net'{
  592.                 return 'pear';
  593.             }
  594.  
  595.             if ($channel == 'pecl.php.net'{
  596.                 return 'pecl';
  597.             }
  598.  
  599.             if ($channel == 'doc.php.net'{
  600.                 return 'phpdocs';
  601.             }
  602.  
  603.             return false;
  604.         }
  605.  
  606.         $channel $this->_getChannel($channel);
  607.         if (PEAR::isError($channel)) {
  608.             return $channel;
  609.         }
  610.  
  611.         return $channel->getAlias();
  612.     }
  613.  
  614.     /**
  615.      * Get the name of the file where data for a given package is stored.
  616.      *
  617.      * @param string channel name, or false if this is a PEAR package
  618.      * @param string package name
  619.      *
  620.      * @return string registry file name
  621.      *
  622.      * @access public
  623.      */
  624.     function _channelDirectoryName($channel)
  625.     {
  626.         if (!$channel || $this->_getChannelFromAlias($channel== 'pear.php.net'{
  627.             return $this->statedir;
  628.         }
  629.  
  630.         $ch $this->_getChannelFromAlias($channel);
  631.         if (!$ch{
  632.             $ch $channel;
  633.         }
  634.  
  635.         return $this->statedir . DIRECTORY_SEPARATOR . strtolower('.channel.' .
  636.             str_replace('/''_'$ch));
  637.     }
  638.  
  639.     function _openPackageFile($package$mode$channel = false)
  640.     {
  641.         if (!$this->_assertStateDir($channel)) {
  642.             return null;
  643.         }
  644.  
  645.         if (!in_array($modearray('r''rb')) && !$this->hasWriteAccess()) {
  646.             return null;
  647.         }
  648.  
  649.         $file $this->_packageFileName($package$channel);
  650.         if (!file_exists($file&& $mode == 'r' || $mode == 'rb'{
  651.             return null;
  652.         }
  653.  
  654.         $fp @fopen($file$mode);
  655.         if (!$fp{
  656.             return null;
  657.         }
  658.  
  659.         return $fp;
  660.     }
  661.  
  662.     function _closePackageFile($fp)
  663.     {
  664.         fclose($fp);
  665.     }
  666.  
  667.     function _openChannelFile($channel$mode)
  668.     {
  669.         if (!$this->_assertChannelDir()) {
  670.             return null;
  671.         }
  672.  
  673.         if (!in_array($modearray('r''rb')) && !$this->hasWriteAccess()) {
  674.             return null;
  675.         }
  676.  
  677.         $file $this->_channelFileName($channel);
  678.         if (!file_exists($file&& $mode == 'r' || $mode == 'rb'{
  679.             return null;
  680.         }
  681.  
  682.         $fp @fopen($file$mode);
  683.         if (!$fp{
  684.             return null;
  685.         }
  686.  
  687.         return $fp;
  688.     }
  689.  
  690.     function _closeChannelFile($fp)
  691.     {
  692.         fclose($fp);
  693.     }
  694.  
  695.     function _rebuildFileMap()
  696.     {
  697.         if (!class_exists('PEAR_Installer_Role')) {
  698.             require_once 'PEAR/Installer/Role.php';
  699.         }
  700.  
  701.         $channels $this->_listAllPackages();
  702.         $files = array();
  703.         foreach ($channels as $channel => $packages{
  704.             foreach ($packages as $package{
  705.                 $version $this->_packageInfo($package'version'$channel);
  706.                 $filelist $this->_packageInfo($package'filelist'$channel);
  707.                 if (!is_array($filelist)) {
  708.                     continue;
  709.                 }
  710.  
  711.                 foreach ($filelist as $name => $attrs{
  712.                     if (isset($attrs['attribs'])) {
  713.                         $attrs $attrs['attribs'];
  714.                     }
  715.  
  716.                     // it is possible for conflicting packages in different channels to
  717.                     // conflict with data files/doc files
  718.                     if ($name == 'dirtree'{
  719.                         continue;
  720.                     }
  721.  
  722.                     if (isset($attrs['role']&& !in_array($attrs['role'],
  723.                           PEAR_Installer_Role::getInstallableRoles())) {
  724.                         // these are not installed
  725.                         continue;
  726.                     }
  727.  
  728.                     if (isset($attrs['role']&& !in_array($attrs['role'],
  729.                           PEAR_Installer_Role::getBaseinstallRoles())) {
  730.                         $attrs['baseinstalldir'$package;
  731.                     }
  732.  
  733.                     if (isset($attrs['baseinstalldir'])) {
  734.                         $file $attrs['baseinstalldir'].DIRECTORY_SEPARATOR.$name;
  735.                     else {
  736.                         $file $name;
  737.                     }
  738.  
  739.                     $file preg_replace(',^/+,'''$file);
  740.                     if ($channel != 'pear.php.net'{
  741.                         if (!isset($files[$attrs['role']])) {
  742.                             $files[$attrs['role']] = array();
  743.                         }
  744.                         $files[$attrs['role']][$file= array(strtolower($channel),
  745.                             strtolower($package));
  746.                     else {
  747.                         if (!isset($files[$attrs['role']])) {
  748.                             $files[$attrs['role']] = array();
  749.                         }
  750.                         $files[$attrs['role']][$filestrtolower($package);
  751.                     }
  752.                 }
  753.             }
  754.         }
  755.  
  756.  
  757.         $this->_assertStateDir();
  758.         if (!$this->hasWriteAccess()) {
  759.             return false;
  760.         }
  761.  
  762.         $fp @fopen($this->filemap'wb');
  763.         if (!$fp{
  764.             return false;
  765.         }
  766.  
  767.         $this->filemap_cache = $files;
  768.         fwrite($fpserialize($files));
  769.         fclose($fp);
  770.         return true;
  771.     }
  772.  
  773.     function _readFileMap()
  774.     {
  775.         if (!file_exists($this->filemap)) {
  776.             return array();
  777.         }
  778.  
  779.         $fp @fopen($this->filemap'r');
  780.         if (!$fp{
  781.             return $this->raiseError('PEAR_Registry: could not open filemap "' $this->filemap . '"'PEAR_REGISTRY_ERROR_FILEnullnull$php_errormsg);
  782.         }
  783.  
  784.         clearstatcache();
  785.         $rt get_magic_quotes_runtime();
  786.         set_magic_quotes_runtime(0);
  787.         $fsize filesize($this->filemap);
  788.         fclose($fp);
  789.         $data file_get_contents($this->filemap);
  790.         set_magic_quotes_runtime($rt);
  791.         $tmp unserialize($data);
  792.         if (!$tmp && $fsize > 7{
  793.             return $this->raiseError('PEAR_Registry: invalid filemap data'PEAR_REGISTRY_ERROR_FORMATnullnull$data);
  794.         }
  795.  
  796.         $this->filemap_cache = $tmp;
  797.         return true;
  798.     }
  799.  
  800.     /**
  801.      * Lock the registry.
  802.      *
  803.      * @param integer lock mode, one of LOCK_EX, LOCK_SH or LOCK_UN.
  804.      *                 See flock manual for more information.
  805.      *
  806.      * @return bool TRUE on success, FALSE if locking failed, or a
  807.      *               PEAR error if some other error occurs (such as the
  808.      *               lock file not being writable).
  809.      *
  810.      * @access private
  811.      */
  812.     function _lock($mode = LOCK_EX)
  813.     {
  814.         if (stristr(php_uname()'Windows 9')) {
  815.             return true;
  816.         }
  817.  
  818.         if ($mode != LOCK_UN && is_resource($this->lock_fp)) {
  819.             // XXX does not check type of lock (LOCK_SH/LOCK_EX)
  820.             return true;
  821.         }
  822.  
  823.         if (!$this->_assertStateDir()) {
  824.             if ($mode == LOCK_EX{
  825.                 return $this->raiseError('Registry directory is not writeable by the current user');
  826.             }
  827.  
  828.             return true;
  829.         }
  830.  
  831.         $open_mode 'w';
  832.         // XXX People reported problems with LOCK_SH and 'w'
  833.         if ($mode === LOCK_SH || $mode === LOCK_UN{
  834.             if (!file_exists($this->lockfile)) {
  835.                 touch($this->lockfile);
  836.             }
  837.             $open_mode 'r';
  838.         }
  839.  
  840.         if (!is_resource($this->lock_fp)) {
  841.             $this->lock_fp = @fopen($this->lockfile$open_mode);
  842.         }
  843.  
  844.         if (!is_resource($this->lock_fp)) {
  845.             $this->lock_fp = null;
  846.             return $this->raiseError("could not create lock file" .
  847.                                      (isset($php_errormsg": " $php_errormsg ""));
  848.         }
  849.  
  850.         if (!(int)flock($this->lock_fp$mode)) {
  851.             switch ($mode{
  852.                 case LOCK_SH: $str 'shared';    break;
  853.                 case LOCK_EX: $str 'exclusive'; break;
  854.                 case LOCK_UN: $str 'unlock';    break;
  855.                 default:      $str 'unknown';   break;
  856.             }
  857.  
  858.             //is resource at this point, close it on error.
  859.             fclose($this->lock_fp);
  860.             $this->lock_fp = null;
  861.             return $this->raiseError("could not acquire $str lock ($this->lockfile)",
  862.                                      PEAR_REGISTRY_ERROR_LOCK);
  863.         }
  864.  
  865.         return true;
  866.     }
  867.  
  868.     function _unlock()
  869.     {
  870.         $ret $this->_lock(LOCK_UN);
  871.         if (is_resource($this->lock_fp)) {
  872.             fclose($this->lock_fp);
  873.         }
  874.  
  875.         $this->lock_fp = null;
  876.         return $ret;
  877.     }
  878.  
  879.     function _packageExists($package$channel = false)
  880.     {
  881.         return file_exists($this->_packageFileName($package$channel));
  882.     }
  883.  
  884.     /**
  885.      * Determine whether a channel exists in the registry
  886.      *
  887.      * @param string Channel name
  888.      * @param bool if true, then aliases will be ignored
  889.      * @return boolean 
  890.      */
  891.     function _channelExists($channel$noaliases = false)
  892.     {
  893.         $a file_exists($this->_channelFileName($channel$noaliases));
  894.         if (!$a && $channel == 'pear.php.net'{
  895.             return true;
  896.         }
  897.  
  898.         if (!$a && $channel == 'pecl.php.net'{
  899.             return true;
  900.         }
  901.  
  902.         if (!$a && $channel == 'doc.php.net'{
  903.             return true;
  904.         }
  905.  
  906.         return $a;
  907.     }
  908.  
  909.     /**
  910.      * Determine whether a mirror exists within the deafult channel in the registry
  911.      *
  912.      * @param string Channel name
  913.      * @param string Mirror name
  914.      *
  915.      * @return boolean 
  916.      */
  917.     function _mirrorExists($channel$mirror)
  918.     {
  919.         $data $this->_channelInfo($channel);
  920.         if (!isset($data['servers']['mirror'])) {
  921.             return false;
  922.         }
  923.  
  924.         foreach ($data['servers']['mirror'as $m{
  925.             if ($m['attribs']['host'== $mirror{
  926.                 return true;
  927.             }
  928.         }
  929.  
  930.         return false;
  931.     }
  932.  
  933.     /**
  934.      * @param PEAR_ChannelFile Channel object
  935.      * @param donotuse 
  936.      * @param string Last-Modified HTTP tag from remote request
  937.      * @return boolean|PEAR_ErrorTrue on creation, false if it already exists
  938.      */
  939.     function _addChannel($channel$update = false$lastmodified = false)
  940.     {
  941.         if (!is_a($channel'PEAR_ChannelFile')) {
  942.             return false;
  943.         }
  944.  
  945.         if (!$channel->validate()) {
  946.             return false;
  947.         }
  948.  
  949.         if (file_exists($this->_channelFileName($channel->getName()))) {
  950.             if (!$update{
  951.                 return false;
  952.             }
  953.  
  954.             $checker $this->_getChannel($channel->getName());
  955.             if (PEAR::isError($checker)) {
  956.                 return $checker;
  957.             }
  958.  
  959.             if ($channel->getAlias(!= $checker->getAlias()) {
  960.                 if (file_exists($this->_getChannelAliasFileName($checker->getAlias()))) {
  961.                     @unlink($this->_getChannelAliasFileName($checker->getAlias()));
  962.                 }
  963.             }
  964.         else {
  965.             if ($update && !in_array($channel->getName()array('pear.php.net''pecl.php.net''doc.php.net'))) {
  966.                 return false;
  967.             }
  968.         }
  969.  
  970.         $ret $this->_assertChannelDir();
  971.         if (PEAR::isError($ret)) {
  972.             return $ret;
  973.         }
  974.  
  975.         $ret $this->_assertChannelStateDir($channel->getName());
  976.         if (PEAR::isError($ret)) {
  977.             return $ret;
  978.         }
  979.  
  980.         if ($channel->getAlias(!= $channel->getName()) {
  981.             if (file_exists($this->_getChannelAliasFileName($channel->getAlias())) &&
  982.                   $this->_getChannelFromAlias($channel->getAlias()) != $channel->getName()) {
  983.                 $channel->setAlias($channel->getName());
  984.             }
  985.  
  986.             if (!$this->hasWriteAccess()) {
  987.                 return false;
  988.             }
  989.  
  990.             $fp @fopen($this->_getChannelAliasFileName($channel->getAlias())'w');
  991.             if (!$fp{
  992.                 return false;
  993.             }
  994.  
  995.             fwrite($fp$channel->getName());
  996.             fclose($fp);
  997.         }
  998.  
  999.         if (!$this->hasWriteAccess()) {
  1000.             return false;
  1001.         }
  1002.  
  1003.         $fp @fopen($this->_channelFileName($channel->getName())'wb');
  1004.         if (!$fp{
  1005.             return false;
  1006.         }
  1007.  
  1008.         $info $channel->toArray();
  1009.         if ($lastmodified{
  1010.             $info['_lastmodified'$lastmodified;
  1011.         else {
  1012.             $info['_lastmodified'date('r');
  1013.         }
  1014.  
  1015.         fwrite($fpserialize($info));
  1016.         fclose($fp);
  1017.         return true;
  1018.     }
  1019.  
  1020.     /**
  1021.      * Deletion fails if there are any packages installed from the channel
  1022.      * @param string|PEAR_ChannelFilechannel name
  1023.      * @return boolean|PEAR_ErrorTrue on deletion, false if it doesn't exist
  1024.      */
  1025.     function _deleteChannel($channel)
  1026.     {
  1027.         if (!is_string($channel)) {
  1028.             if (!is_a($channel'PEAR_ChannelFile')) {
  1029.                 return false;
  1030.             }
  1031.  
  1032.             if (!$channel->validate()) {
  1033.                 return false;
  1034.             }
  1035.             $channel $channel->getName();
  1036.         }
  1037.  
  1038.         if ($this->_getChannelFromAlias($channel== '__uri'{
  1039.             return false;
  1040.         }
  1041.  
  1042.         if ($this->_getChannelFromAlias($channel== 'pecl.php.net'{
  1043.             return false;
  1044.         }
  1045.  
  1046.         if ($this->_getChannelFromAlias($channel== 'doc.php.net'{
  1047.             return false;
  1048.         }
  1049.  
  1050.         if (!$this->_channelExists($channel)) {
  1051.             return false;
  1052.         }
  1053.  
  1054.         if (!$channel || $this->_getChannelFromAlias($channel== 'pear.php.net'{
  1055.             return false;
  1056.         }
  1057.  
  1058.         $channel $this->_getChannelFromAlias($channel);
  1059.         if ($channel == 'pear.php.net'{
  1060.             return false;
  1061.         }
  1062.  
  1063.         $test $this->_listChannelPackages($channel);
  1064.         if (count($test)) {
  1065.             return false;
  1066.         }
  1067.  
  1068.         $test @rmdir($this->_channelDirectoryName($channel));
  1069.         if (!$test{
  1070.             return false;
  1071.         }
  1072.  
  1073.         $file $this->_getChannelAliasFileName($this->_getAlias($channel));
  1074.         if (file_exists($file)) {
  1075.             $test @unlink($file);
  1076.             if (!$test{
  1077.                 return false;
  1078.             }
  1079.         }
  1080.  
  1081.         $file $this->_channelFileName($channel);
  1082.         $ret = true;
  1083.         if (file_exists($file)) {
  1084.             $ret @unlink($file);
  1085.         }
  1086.  
  1087.         return $ret;
  1088.     }
  1089.  
  1090.     /**
  1091.      * Determine whether a channel exists in the registry
  1092.      * @param string Channel Alias
  1093.      * @return boolean 
  1094.      */
  1095.     function _isChannelAlias($alias)
  1096.     {
  1097.         return file_exists($this->_getChannelAliasFileName($alias));
  1098.     }
  1099.  
  1100.     /**
  1101.      * @param string|null
  1102.      * @param string|null
  1103.      * @param string|null
  1104.      * @return array|null
  1105.      * @access private
  1106.      */
  1107.     function _packageInfo($package = null$key = null$channel 'pear.php.net')
  1108.     {
  1109.         if ($package === null{
  1110.             if ($channel === null{
  1111.                 $channels $this->_listChannels();
  1112.                 $ret = array();
  1113.                 foreach ($channels as $channel{
  1114.                     $channel strtolower($channel);
  1115.                     $ret[$channel= array();
  1116.                     $packages $this->_listPackages($channel);
  1117.                     foreach ($packages as $package{
  1118.                         $ret[$channel][$this->_packageInfo($packagenull$channel);
  1119.                     }
  1120.                 }
  1121.  
  1122.                 return $ret;
  1123.             }
  1124.  
  1125.             $ps $this->_listPackages($channel);
  1126.             if (!count($ps)) {
  1127.                 return array();
  1128.             }
  1129.             return array_map(array(&$this'_packageInfo'),
  1130.                              $psarray_fill(0count($ps)null),
  1131.                              array_fill(0count($ps)$channel));
  1132.         }
  1133.  
  1134.         $fp $this->_openPackageFile($package'r'$channel);
  1135.         if ($fp === null{
  1136.             return null;
  1137.         }
  1138.  
  1139.         $rt get_magic_quotes_runtime();
  1140.         set_magic_quotes_runtime(0);
  1141.         clearstatcache();
  1142.         $this->_closePackageFile($fp);
  1143.         $data file_get_contents($this->_packageFileName($package$channel));
  1144.         set_magic_quotes_runtime($rt);
  1145.         $data unserialize($data);
  1146.         if ($key === null{
  1147.             return $data;
  1148.         }
  1149.  
  1150.         // compatibility for package.xml version 2.0
  1151.         if (isset($data['old'][$key])) {
  1152.             return $data['old'][$key];
  1153.         }
  1154.  
  1155.         if (isset($data[$key])) {
  1156.             return $data[$key];
  1157.         }
  1158.  
  1159.         return null;
  1160.     }
  1161.  
  1162.     /**
  1163.      * @param string Channel name
  1164.      * @param bool whether to strictly retrieve info of channels, not just aliases
  1165.      * @return array|null
  1166.      */
  1167.     function _channelInfo($channel$noaliases = false)
  1168.     {
  1169.         if (!$this->_channelExists($channel$noaliases)) {
  1170.             return null;
  1171.         }
  1172.  
  1173.         $fp $this->_openChannelFile($channel'r');
  1174.         if ($fp === null{
  1175.             return null;
  1176.         }
  1177.  
  1178.         $rt get_magic_quotes_runtime();
  1179.         set_magic_quotes_runtime(0);
  1180.         clearstatcache();
  1181.         $this->_closeChannelFile($fp);
  1182.         $data file_get_contents($this->_channelFileName($channel));
  1183.         set_magic_quotes_runtime($rt);
  1184.         $data unserialize($data);
  1185.         return $data;
  1186.     }
  1187.  
  1188.     function _listChannels()
  1189.     {
  1190.         $channellist = array();
  1191.         if (!file_exists($this->channelsdir|| !is_dir($this->channelsdir)) {
  1192.             return array('pear.php.net''pecl.php.net''doc.php.net''__uri');
  1193.         }
  1194.  
  1195.         $dp opendir($this->channelsdir);
  1196.         while ($ent readdir($dp)) {
  1197.             if ($ent{0== '.' || substr($ent-4!= '.reg'{
  1198.                 continue;
  1199.             }
  1200.  
  1201.             if ($ent == '__uri.reg'{
  1202.                 $channellist['__uri';
  1203.                 continue;
  1204.             }
  1205.  
  1206.             $channellist[str_replace('_''/'substr($ent0-4));
  1207.         }
  1208.  
  1209.         closedir($dp);
  1210.         if (!in_array('pear.php.net'$channellist)) {
  1211.             $channellist['pear.php.net';
  1212.         }
  1213.  
  1214.         if (!in_array('pecl.php.net'$channellist)) {
  1215.             $channellist['pecl.php.net';
  1216.         }
  1217.  
  1218.         if (!in_array('doc.php.net'$channellist)) {
  1219.             $channellist['doc.php.net';
  1220.         }
  1221.  
  1222.  
  1223.         if (!in_array('__uri'$channellist)) {
  1224.             $channellist['__uri';
  1225.         }
  1226.  
  1227.         natsort($channellist);
  1228.         return $channellist;
  1229.     }
  1230.  
  1231.     function _listPackages($channel = false)
  1232.     {
  1233.         if ($channel && $this->_getChannelFromAlias($channel!= 'pear.php.net'{
  1234.             return $this->_listChannelPackages($channel);
  1235.         }
  1236.  
  1237.         if (!file_exists($this->statedir|| !is_dir($this->statedir)) {
  1238.             return array();
  1239.         }
  1240.  
  1241.         $pkglist = array();
  1242.         $dp opendir($this->statedir);
  1243.         if (!$dp{
  1244.             return $pkglist;
  1245.         }
  1246.  
  1247.         while ($ent readdir($dp)) {
  1248.             if ($ent{0== '.' || substr($ent-4!= '.reg'{
  1249.                 continue;
  1250.             }
  1251.  
  1252.             $pkglist[substr($ent0-4);
  1253.         }
  1254.         closedir($dp);
  1255.         return $pkglist;
  1256.     }
  1257.  
  1258.     function _listChannelPackages($channel)
  1259.     {
  1260.         $pkglist = array();
  1261.         if (!file_exists($this->_channelDirectoryName($channel)) ||
  1262.               !is_dir($this->_channelDirectoryName($channel))) {
  1263.             return array();
  1264.         }
  1265.  
  1266.         $dp opendir($this->_channelDirectoryName($channel));
  1267.         if (!$dp{
  1268.             return $pkglist;
  1269.         }
  1270.  
  1271.         while ($ent readdir($dp)) {
  1272.             if ($ent{0== '.' || substr($ent-4!= '.reg'{
  1273.                 continue;
  1274.             }
  1275.             $pkglist[substr($ent0-4);
  1276.         }
  1277.  
  1278.         closedir($dp);
  1279.         return $pkglist;
  1280.     }
  1281.  
  1282.     function _listAllPackages()
  1283.     {
  1284.         $ret = array();
  1285.         foreach ($this->_listChannels(as $channel{
  1286.             $ret[$channel$this->_listPackages($channel);
  1287.         }
  1288.  
  1289.         return $ret;
  1290.     }
  1291.  
  1292.     /**
  1293.      * Add an installed package to the registry
  1294.      * @param string package name
  1295.      * @param array package info (parsed by PEAR_Common::infoFrom*() methods)
  1296.      * @return bool success of saving
  1297.      * @access private
  1298.      */
  1299.     function _addPackage($package$info)
  1300.     {
  1301.         if ($this->_packageExists($package)) {
  1302.             return false;
  1303.         }
  1304.  
  1305.         $fp $this->_openPackageFile($package'wb');
  1306.         if ($fp === null{
  1307.             return false;
  1308.         }
  1309.  
  1310.         $info['_lastmodified'time();
  1311.         fwrite($fpserialize($info));
  1312.         $this->_closePackageFile($fp);
  1313.         if (isset($info['filelist'])) {
  1314.             $this->_rebuildFileMap();
  1315.         }
  1316.  
  1317.         return true;
  1318.     }
  1319.  
  1320.     /**
  1321.      * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  1322.      * @return bool 
  1323.      * @access private
  1324.      */
  1325.     function _addPackage2($info)
  1326.     {
  1327.         if (!is_a($info'PEAR_PackageFile_v1'&& !is_a($info'PEAR_PackageFile_v2')) {
  1328.             return false;
  1329.         }
  1330.  
  1331.         if (!$info->validate()) {
  1332.             if (class_exists('PEAR_Common')) {
  1333.                 $ui PEAR_Frontend::singleton();
  1334.                 if ($ui{
  1335.                     foreach ($info->getValidationWarnings(as $err{
  1336.                         $ui->log($err['message']true);
  1337.                     }
  1338.                 }
  1339.             }
  1340.             return false;
  1341.         }
  1342.  
  1343.         $channel $info->getChannel();
  1344.         $package $info->getPackage();
  1345.         $save $info;
  1346.         if ($this->_packageExists($package$channel)) {
  1347.             return false;
  1348.         }
  1349.  
  1350.         if (!$this->_channelExists($channeltrue)) {
  1351.             return false;
  1352.         }
  1353.  
  1354.         $info $info->toArray(true);
  1355.         if (!$info{
  1356.             return false;
  1357.         }
  1358.  
  1359.         $fp $this->_openPackageFile($package'wb'$channel);
  1360.         if ($fp === null{
  1361.             return false;
  1362.         }
  1363.  
  1364.         $info['_lastmodified'time();
  1365.         fwrite($fpserialize($info));
  1366.         $this->_closePackageFile($fp);
  1367.         $this->_rebuildFileMap();
  1368.         return true;
  1369.     }
  1370.  
  1371.     /**
  1372.      * @param string Package name
  1373.      * @param array parsed package.xml 1.0
  1374.      * @param bool this parameter is only here for BC.  Don't use it.
  1375.      * @access private
  1376.      */
  1377.     function _updatePackage($package$info$merge = true)
  1378.     {
  1379.         $oldinfo $this->_packageInfo($package);
  1380.         if (empty($oldinfo)) {
  1381.             return false;
  1382.         }
  1383.  
  1384.         $fp $this->_openPackageFile($package'w');
  1385.         if ($fp === null{
  1386.             return false;
  1387.         }
  1388.  
  1389.         if (is_object($info)) {
  1390.             $info $info->toArray();
  1391.         }
  1392.         $info['_lastmodified'time();
  1393.  
  1394.         $newinfo $info;
  1395.         if ($merge{
  1396.             $info array_merge($oldinfo$info);
  1397.         else {
  1398.             $diff $info;
  1399.         }
  1400.  
  1401.         fwrite($fpserialize($info));
  1402.         $this->_closePackageFile($fp);
  1403.         if (isset($newinfo['filelist'])) {
  1404.             $this->_rebuildFileMap();
  1405.         }
  1406.  
  1407.         return true;
  1408.     }
  1409.  
  1410.     /**
  1411.      * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  1412.      * @return bool 
  1413.      * @access private
  1414.      */
  1415.     function _updatePackage2($info)
  1416.     {
  1417.         if (!$this->_packageExists($info->getPackage()$info->getChannel())) {
  1418.             return false;
  1419.         }
  1420.  
  1421.         $fp $this->_openPackageFile($info->getPackage()'w'$info->getChannel());
  1422.         if ($fp === null{
  1423.             return false;
  1424.         }
  1425.  
  1426.         $save $info;
  1427.         $info $save->getArray(true);
  1428.         $info['_lastmodified'time();
  1429.         fwrite($fpserialize($info));
  1430.         $this->_closePackageFile($fp);
  1431.         $this->_rebuildFileMap();
  1432.         return true;
  1433.     }
  1434.  
  1435.     /**
  1436.      * @param string Package name
  1437.      * @param string Channel name
  1438.      * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|null
  1439.      * @access private
  1440.      */
  1441.     function &_getPackage($package$channel 'pear.php.net')
  1442.     {
  1443.         $info $this->_packageInfo($packagenull$channel);
  1444.         if ($info === null{
  1445.             return $info;
  1446.         }
  1447.  
  1448.         $a $this->_config;
  1449.         if (!$a{
  1450.             $this->_config = &new PEAR_Config;
  1451.             $this->_config->set('php_dir'$this->statedir);
  1452.         }
  1453.  
  1454.         if (!class_exists('PEAR_PackageFile')) {
  1455.             require_once 'PEAR/PackageFile.php';
  1456.         }
  1457.  
  1458.         $pkg &new PEAR_PackageFile($this->_config);
  1459.         $pf &$pkg->fromArray($info);
  1460.         return $pf;
  1461.     }
  1462.  
  1463.     /**
  1464.      * @param string channel name
  1465.      * @param bool whether to strictly retrieve channel names
  1466.      * @return PEAR_ChannelFile|PEAR_Error
  1467.      * @access private
  1468.      */
  1469.     function &_getChannel($channel$noaliases = false)
  1470.     {
  1471.         $ch = false;
  1472.         if ($this->_channelExists($channel$noaliases)) {
  1473.             $chinfo $this->_channelInfo($channel$noaliases);
  1474.             if ($chinfo{
  1475.                 if (!class_exists('PEAR_ChannelFile')) {
  1476.                     require_once 'PEAR/ChannelFile.php';
  1477.                 }
  1478.  
  1479.                 $ch &PEAR_ChannelFile::fromArrayWithErrors($chinfo);
  1480.             }
  1481.         }
  1482.  
  1483.         if ($ch{
  1484.             if ($ch->validate()) {
  1485.                 return $ch;
  1486.             }
  1487.  
  1488.             foreach ($ch->getErrors(trueas $err{
  1489.                 $message $err['message'"\n";
  1490.             }
  1491.  
  1492.             $ch PEAR::raiseError($message);
  1493.             return $ch;
  1494.         }
  1495.  
  1496.         if ($this->_getChannelFromAlias($channel== 'pear.php.net'{
  1497.             // the registry is not properly set up, so use defaults
  1498.             if (!class_exists('PEAR_ChannelFile')) {
  1499.                 require_once 'PEAR/ChannelFile.php';
  1500.             }
  1501.  
  1502.             $pear_channel = new PEAR_ChannelFile;
  1503.             $pear_channel->setServer('pear.php.net');
  1504.             $pear_channel->setAlias('pear');
  1505.             $pear_channel->setSummary('PHP Extension and Application Repository');
  1506.             $pear_channel->setDefaultPEARProtocols();
  1507.             $pear_channel->setBaseURL('REST1.0''http://pear.php.net/rest/');
  1508.             $pear_channel->setBaseURL('REST1.1''http://pear.php.net/rest/');
  1509.             $pear_channel->setBaseURL('REST1.3''http://pear.php.net/rest/');
  1510.             return $pear_channel;
  1511.         }
  1512.  
  1513.         if ($this->_getChannelFromAlias($channel== 'pecl.php.net'{
  1514.             // the registry is not properly set up, so use defaults
  1515.             if (!class_exists('PEAR_ChannelFile')) {
  1516.                 require_once 'PEAR/ChannelFile.php';
  1517.             }
  1518.             $pear_channel = new PEAR_ChannelFile;
  1519.             $pear_channel->setServer('pecl.php.net');
  1520.             $pear_channel->setAlias('pecl');
  1521.             $pear_channel->setSummary('PHP Extension Community Library');
  1522.             $pear_channel->setDefaultPEARProtocols();
  1523.             $pear_channel->setBaseURL('REST1.0''http://pecl.php.net/rest/');
  1524.             $pear_channel->setBaseURL('REST1.1''http://pecl.php.net/rest/');
  1525.             $pear_channel->setValidationPackage('PEAR_Validator_PECL''1.0');
  1526.             return $pear_channel;
  1527.         }
  1528.  
  1529.         if ($this->_getChannelFromAlias($channel== 'doc.php.net'{
  1530.             // the registry is not properly set up, so use defaults
  1531.             if (!class_exists('PEAR_ChannelFile')) {
  1532.                 require_once 'PEAR/ChannelFile.php';
  1533.             }
  1534.  
  1535.             $doc_channel = new PEAR_ChannelFile;
  1536.             $doc_channel->setServer('doc.php.net');
  1537.             $doc_channel->setAlias('phpdocs');
  1538.             $doc_channel->setSummary('PHP Documentation Team');
  1539.             $doc_channel->setDefaultPEARProtocols();
  1540.             $doc_channel->setBaseURL('REST1.0''http://doc.php.net/rest/');
  1541.             $doc_channel->setBaseURL('REST1.1''http://doc.php.net/rest/');
  1542.             $doc_channel->setBaseURL('REST1.3''http://doc.php.net/rest/');
  1543.             return $doc_channel;
  1544.         }
  1545.  
  1546.  
  1547.         if ($this->_getChannelFromAlias($channel== '__uri'{
  1548.             // the registry is not properly set up, so use defaults
  1549.             if (!class_exists('PEAR_ChannelFile')) {
  1550.                 require_once 'PEAR/ChannelFile.php';
  1551.             }
  1552.  
  1553.             $private = new PEAR_ChannelFile;
  1554.             $private->setName('__uri');
  1555.             $private->setDefaultPEARProtocols();
  1556.             $private->setBaseURL('REST1.0''****');
  1557.             $private->setSummary('Pseudo-channel for static packages');
  1558.             return $private;
  1559.         }
  1560.  
  1561.         return $ch;
  1562.     }
  1563.  
  1564.     /**
  1565.      * @param string Package name
  1566.      * @param string Channel name
  1567.      * @return bool 
  1568.      */
  1569.     function packageExists($package$channel 'pear.php.net')
  1570.     {
  1571.         if (PEAR::isError($e $this->_lock(LOCK_SH))) {
  1572.             return $e;
  1573.         }
  1574.         $ret $this->_packageExists($package$channel);
  1575.         $this->_unlock();
  1576.         return $ret;
  1577.     }
  1578.  
  1579.     // }}}
  1580.  
  1581.     // {{{ channelExists()
  1582.  
  1583.     /**
  1584.      * @param string channel name
  1585.      * @param bool if true, then aliases will be ignored
  1586.      * @return bool 
  1587.      */
  1588.     function channelExists($channel$noaliases = false)
  1589.     {
  1590.         if (PEAR::isError($e $this->_lock(LOCK_SH))) {
  1591.             return $e;
  1592.         }
  1593.         $ret $this->_channelExists($channel$noaliases);
  1594.         $this->_unlock();
  1595.         return $ret;
  1596.     }
  1597.  
  1598.     // }}}
  1599.  
  1600.     /**
  1601.      * @param string channel name mirror is in
  1602.      * @param string mirror name
  1603.      *
  1604.      * @return bool 
  1605.      */
  1606.     function mirrorExists($channel$mirror)
  1607.     {
  1608.         if (PEAR::isError($e $this->_lock(LOCK_SH))) {
  1609.             return $e;
  1610.         }
  1611.  
  1612.         $ret $this->_mirrorExists($channel$mirror);
  1613.         $this->_unlock();
  1614.         return $ret;
  1615.     }
  1616.  
  1617.     // {{{ isAlias()
  1618.  
  1619.     /**
  1620.      * Determines whether the parameter is an alias of a channel
  1621.      * @param string 
  1622.      * @return bool 
  1623.      */
  1624.     function isAlias($alias)
  1625.     {
  1626.         if (PEAR::isError($e $this->_lock(LOCK_SH))) {
  1627.             return $e;
  1628.         }
  1629.         $ret $this->_isChannelAlias($alias);
  1630.         $this->_unlock();
  1631.         return $ret;
  1632.     }
  1633.  
  1634.     // }}}
  1635.     // {{{ packageInfo()
  1636.  
  1637.     /**
  1638.      * @param string|null
  1639.      * @param string|null
  1640.      * @param string 
  1641.      * @return array|null
  1642.      */
  1643.     function packageInfo($package = null$key = null$channel 'pear.php.net')
  1644.     {
  1645.         if (PEAR::isError($e $this->_lock(LOCK_SH))) {
  1646.             return $e;
  1647.         }
  1648.         $ret $this->_packageInfo($package$key$channel);
  1649.         $this->_unlock();
  1650.         return $ret;
  1651.     }
  1652.  
  1653.     // }}}
  1654.     // {{{ channelInfo()
  1655.  
  1656.     /**
  1657.      * Retrieve a raw array of channel data.
  1658.      *
  1659.      * Do not use this, instead use {@link getChannel()} for normal
  1660.      * operations.  Array structure is undefined in this method
  1661.      * @param string channel name
  1662.      * @param bool whether to strictly retrieve information only on non-aliases
  1663.      * @return array|null|PEAR_Error
  1664.      */
  1665.     function channelInfo($channel = null$noaliases = false)
  1666.     {
  1667.         if (PEAR::isError($e $this->_lock(LOCK_SH))) {
  1668.             return $e;
  1669.         }
  1670.         $ret $this->_channelInfo($channel$noaliases);
  1671.         $this->_unlock();
  1672.         return $ret;
  1673.     }
  1674.  
  1675.     // }}}
  1676.  
  1677.     /**
  1678.      * @param string 
  1679.      */
  1680.     function channelName($channel)
  1681.     {
  1682.         if (PEAR::isError($e $this->_lock(LOCK_SH))) {
  1683.             return $e;
  1684.         }
  1685.         $ret $this->_getChannelFromAlias($channel);
  1686.         $this->_unlock();
  1687.         return $ret;
  1688.     }
  1689.  
  1690.     /**
  1691.      * @param string 
  1692.      */
  1693.     function channelAlias($channel)
  1694.     {
  1695.         if (PEAR::isError($e $this->_lock(LOCK_SH))) {
  1696.             return $e;
  1697.         }
  1698.         $ret $this->_getAlias($channel);
  1699.         $this->_unlock();
  1700.         return $ret;
  1701.     }
  1702.     // {{{ listPackages()
  1703.  
  1704.     function listPackages($channel = false)
  1705.     {
  1706.         if (PEAR::isError($e $this->_lock(LOCK_SH))) {
  1707.             return $e;
  1708.         }
  1709.         $ret $this->_listPackages($channel);
  1710.         $this->_unlock();
  1711.         return $ret;
  1712.     }
  1713.  
  1714.     // }}}
  1715.     // {{{ listAllPackages()
  1716.  
  1717.     function listAllPackages()
  1718.     {
  1719.         if (PEAR::isError($e $this->_lock(LOCK_SH))) {
  1720.             return $e;
  1721.         }
  1722.         $ret $this->_listAllPackages();
  1723.         $this->_unlock();
  1724.         return $ret;
  1725.     }
  1726.  
  1727.     // }}}
  1728.     // {{{ listChannel()
  1729.  
  1730.     function listChannels()
  1731.     {
  1732.         if (PEAR::isError($e $this->_lock(LOCK_SH))) {
  1733.             return $e;
  1734.         }
  1735.         $ret $this->_listChannels();
  1736.         $this->_unlock();
  1737.         return $ret;
  1738.     }
  1739.  
  1740.     // }}}
  1741.     // {{{ addPackage()
  1742.  
  1743.     /**
  1744.      * Add an installed package to the registry
  1745.      * @param string|PEAR_PackageFile_v1|PEAR_PackageFile_v2package name or object
  1746.      *                that will be passed to {@link addPackage2()}
  1747.      * @param array package info (parsed by PEAR_Common::infoFrom*() methods)
  1748.      * @return bool success of saving
  1749.      */
  1750.     function addPackage($package$info)
  1751.     {
  1752.         if (is_object($info)) {
  1753.             return $this->addPackage2($info);
  1754.         }
  1755.         if (PEAR::isError($e $this->_lock(LOCK_EX))) {
  1756.             return $e;
  1757.         }
  1758.         $ret $this->_addPackage($package$info);
  1759.         $this->_unlock();
  1760.         if ($ret{
  1761.             if (!class_exists('PEAR_PackageFile_v1')) {
  1762.                 require_once 'PEAR/PackageFile/v1.php';
  1763.             }
  1764.             $pf = new PEAR_PackageFile_v1;
  1765.             $pf->setConfig($this->_config);
  1766.             $pf->fromArray($info);
  1767.             $this->_dependencyDB->uninstallPackage($pf);
  1768.             $this->_dependencyDB->installPackage($pf);
  1769.         }
  1770.         return $ret;
  1771.     }
  1772.  
  1773.     // }}}
  1774.     // {{{ addPackage2()
  1775.  
  1776.     function addPackage2($info)
  1777.     {
  1778.         if (!is_object($info)) {
  1779.             return $this->addPackage($info['package']$info);
  1780.         }
  1781.         if (PEAR::isError($e $this->_lock(LOCK_EX))) {
  1782.             return $e;
  1783.         }
  1784.         $ret $this->_addPackage2($info);
  1785.         $this->_unlock();
  1786.         if ($ret{
  1787.             $this->_dependencyDB->uninstallPackage($info);
  1788.             $this->_dependencyDB->installPackage($info);
  1789.         }
  1790.         return $ret;
  1791.     }
  1792.  
  1793.     // }}}
  1794.     // {{{ updateChannel()
  1795.  
  1796.     /**
  1797.      * For future expandibility purposes, separate this
  1798.      * @param PEAR_ChannelFile 
  1799.      */
  1800.     function updateChannel($channel$lastmodified = null)
  1801.     {
  1802.         if ($channel->getName(== '__uri'{
  1803.             return false;
  1804.         }
  1805.         return $this->addChannel($channel$lastmodifiedtrue);
  1806.     }
  1807.  
  1808.     // }}}
  1809.     // {{{ deleteChannel()
  1810.  
  1811.     /**
  1812.      * Deletion fails if there are any packages installed from the channel
  1813.      * @param string|PEAR_ChannelFilechannel name
  1814.      * @return boolean|PEAR_ErrorTrue on deletion, false if it doesn't exist
  1815.      */
  1816.     function deleteChannel($channel)
  1817.     {
  1818.         if (PEAR::isError($e $this->_lock(LOCK_EX))) {
  1819.             return $e;
  1820.         }
  1821.  
  1822.         $ret $this->_deleteChannel($channel);
  1823.         $this->_unlock();
  1824.         if ($ret && is_a($this->_config'PEAR_Config')) {
  1825.             $this->_config->setChannels($this->listChannels());
  1826.         }
  1827.  
  1828.         return $ret;
  1829.     }
  1830.  
  1831.     // }}}
  1832.     // {{{ addChannel()
  1833.  
  1834.     /**
  1835.      * @param PEAR_ChannelFile Channel object
  1836.      * @param string Last-Modified header from HTTP for caching
  1837.      * @return boolean|PEAR_ErrorTrue on creation, false if it already exists
  1838.      */
  1839.     function addChannel($channel$lastmodified = false$update = false)
  1840.     {
  1841.         if (!is_a($channel'PEAR_ChannelFile'|| !$channel->validate()) {
  1842.             return false;
  1843.         }
  1844.  
  1845.         if (PEAR::isError($e $this->_lock(LOCK_EX))) {
  1846.             return $e;
  1847.         }
  1848.  
  1849.         $ret $this->_addChannel($channel$update$lastmodified);
  1850.         $this->_unlock();
  1851.         if (!$update && $ret && is_a($this->_config'PEAR_Config')) {
  1852.             $this->_config->setChannels($this->listChannels());
  1853.         }
  1854.  
  1855.         return $ret;
  1856.     }
  1857.  
  1858.     // }}}
  1859.     // {{{ deletePackage()
  1860.  
  1861.     function deletePackage($package$channel 'pear.php.net')
  1862.     {
  1863.         if (PEAR::isError($e $this->_lock(LOCK_EX))) {
  1864.             return $e;
  1865.         }
  1866.  
  1867.         $file $this->_packageFileName($package$channel);
  1868.         $ret  file_exists($file@unlink($file: false;
  1869.         $this->_rebuildFileMap();
  1870.         $this->_unlock();
  1871.         $p = array('channel' => $channel'package' => $package);
  1872.         $this->_dependencyDB->uninstallPackage($p);
  1873.         return $ret;
  1874.     }
  1875.  
  1876.     // }}}
  1877.     // {{{ updatePackage()
  1878.  
  1879.     function updatePackage($package$info$merge = true)
  1880.     {
  1881.         if (is_object($info)) {
  1882.             return $this->updatePackage2($info$merge);
  1883.         }
  1884.         if (PEAR::isError($e $this->_lock(LOCK_EX))) {
  1885.             return $e;
  1886.         }
  1887.         $ret $this->_updatePackage($package$info$merge);
  1888.         $this->_unlock();
  1889.         if ($ret{
  1890.             if (!class_exists('PEAR_PackageFile_v1')) {
  1891.                 require_once 'PEAR/PackageFile/v1.php';
  1892.             }
  1893.             $pf = new PEAR_PackageFile_v1;
  1894.             $pf->setConfig($this->_config);
  1895.             $pf->fromArray($this->packageInfo($package));
  1896.             $this->_dependencyDB->uninstallPackage($pf);
  1897.             $this->_dependencyDB->installPackage($pf);
  1898.         }
  1899.         return $ret;
  1900.     }
  1901.  
  1902.     // }}}
  1903.     // {{{ updatePackage2()
  1904.  
  1905.     function updatePackage2($info)
  1906.     {
  1907.  
  1908.         if (!is_object($info)) {
  1909.             return $this->updatePackage($info['package']$info$merge);
  1910.         }
  1911.  
  1912.         if (!$info->validate(PEAR_VALIDATE_DOWNLOADING)) {
  1913.             return false;
  1914.         }
  1915.  
  1916.         if (PEAR::isError($e $this->_lock(LOCK_EX))) {
  1917.             return $e;
  1918.         }
  1919.  
  1920.         $ret $this->_updatePackage2($info);
  1921.         $this->_unlock();
  1922.         if ($ret{
  1923.             $this->_dependencyDB->uninstallPackage($info);
  1924.             $this->_dependencyDB->installPackage($info);
  1925.         }
  1926.  
  1927.         return $ret;
  1928.     }
  1929.  
  1930.     // }}}
  1931.     // {{{ getChannel()
  1932.     /**
  1933.      * @param string channel name
  1934.      * @param bool whether to strictly return raw channels (no aliases)
  1935.      * @return PEAR_ChannelFile|PEAR_Error
  1936.      */
  1937.     function &getChannel($channel$noaliases = false)
  1938.     {
  1939.         if (PEAR::isError($e $this->_lock(LOCK_SH))) {
  1940.             return $e;
  1941.         }
  1942.         $ret &$this->_getChannel($channel$noaliases);
  1943.         $this->_unlock();
  1944.         if (!$ret{
  1945.             return PEAR::raiseError('Unknown channel: ' $channel);
  1946.         }
  1947.         return $ret;
  1948.     }
  1949.  
  1950.     // }}}
  1951.     // {{{ getPackage()
  1952.     /**
  1953.      * @param string package name
  1954.      * @param string channel name
  1955.      * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|null
  1956.      */
  1957.     function &getPackage($package$channel 'pear.php.net')
  1958.     {
  1959.         if (PEAR::isError($e $this->_lock(LOCK_SH))) {
  1960.             return $e;
  1961.         }
  1962.         $pf &$this->_getPackage($package$channel);
  1963.         $this->_unlock();
  1964.         return $pf;
  1965.     }
  1966.  
  1967.     // }}}
  1968.  
  1969.     /**
  1970.      * Get PEAR_PackageFile_v[1/2] objects representing the contents of
  1971.      * a dependency group that are installed.
  1972.      *
  1973.      * This is used at uninstall-time
  1974.      * @param array 
  1975.      * @return array|false
  1976.      */
  1977.     function getInstalledGroup($group)
  1978.     {
  1979.         $ret = array();
  1980.         if (isset($group['package'])) {
  1981.             if (!isset($group['package'][0])) {
  1982.                 $group['package'= array($group['package']);
  1983.             }
  1984.             foreach ($group['package'as $package{
  1985.                 $depchannel = isset($package['channel']$package['channel''__uri';
  1986.                 $p &$this->getPackage($package['name']$depchannel);
  1987.                 if ($p{
  1988.                     $save &$p;
  1989.                     $ret[&$save;
  1990.                 }
  1991.             }
  1992.         }
  1993.         if (isset($group['subpackage'])) {
  1994.             if (!isset($group['subpackage'][0])) {
  1995.                 $group['subpackage'= array($group['subpackage']);
  1996.             }
  1997.             foreach ($group['subpackage'as $package{
  1998.                 $depchannel = isset($package['channel']$package['channel''__uri';
  1999.                 $p &$this->getPackage($package['name']$depchannel);
  2000.                 if ($p{
  2001.                     $save &$p;
  2002.                     $ret[&$save;
  2003.                 }
  2004.             }
  2005.         }
  2006.         if (!count($ret)) {
  2007.             return false;
  2008.         }
  2009.         return $ret;
  2010.     }
  2011.  
  2012.     // {{{ getChannelValidator()
  2013.     /**
  2014.      * @param string channel name
  2015.      * @return PEAR_Validate|false
  2016.      */
  2017.     function &getChannelValidator($channel)
  2018.     {
  2019.         $chan $this->getChannel($channel);
  2020.         if (PEAR::isError($chan)) {
  2021.             return $chan;
  2022.         }
  2023.         $val $chan->getValidationObject();
  2024.         return $val;
  2025.     }
  2026.     // }}}
  2027.     // {{{ getChannels()
  2028.     /**
  2029.      * @param string channel name
  2030.      * @return array an array of PEAR_ChannelFile objects representing every installed channel
  2031.      */
  2032.     function &getChannels()
  2033.     {
  2034.         $ret = array();
  2035.         if (PEAR::isError($e $this->_lock(LOCK_SH))) {
  2036.             return $e;
  2037.         }
  2038.         foreach ($this->_listChannels(as $channel{
  2039.             $e &$this->_getChannel($channel);
  2040.             if (!$e || PEAR::isError($e)) {
  2041.                 continue;
  2042.             }
  2043.             $ret[$e;
  2044.         }
  2045.         $this->_unlock();
  2046.         return $ret;
  2047.     }
  2048.  
  2049.     // }}}
  2050.     // {{{ checkFileMap()
  2051.  
  2052.     /**
  2053.      * Test whether a file or set of files belongs to a package.
  2054.      *
  2055.      * If an array is passed in
  2056.      * @param string|arrayfile path, absolute or relative to the pear
  2057.      *                      install dir
  2058.      * @param string|arrayname of PEAR package or array('package' => name, 'channel' =>
  2059.      *                      channel) of a package that will be ignored
  2060.      * @param string API version - 1.1 will exclude any files belonging to a package
  2061.      * @param array private recursion variable
  2062.      * @return array|falsewhich package and channel the file belongs to, or an empty
  2063.      *                      string if the file does not belong to an installed package,
  2064.      *                      or belongs to the second parameter's package
  2065.      */
  2066.     function checkFileMap($path$package = false$api '1.0'$attrs = false)
  2067.     {
  2068.         if (is_array($path)) {
  2069.             static $notempty;
  2070.             if (empty($notempty)) {
  2071.                 if (!class_exists('PEAR_Installer_Role')) {
  2072.                     require_once 'PEAR/Installer/Role.php';
  2073.                 }
  2074.                 $notempty create_function('$a','return !empty($a);');
  2075.             }
  2076.             $package is_array($package? array(strtolower($package[0])strtolower($package[1]))
  2077.                 : strtolower($package);
  2078.             $pkgs = array();
  2079.             foreach ($path as $name => $attrs{
  2080.                 if (is_array($attrs)) {
  2081.                     if (isset($attrs['install-as'])) {
  2082.                         $name $attrs['install-as'];
  2083.                     }
  2084.                     if (!in_array($attrs['role']PEAR_Installer_Role::getInstallableRoles())) {
  2085.                         // these are not installed
  2086.                         continue;
  2087.                     }
  2088.                     if (!in_array($attrs['role']PEAR_Installer_Role::getBaseinstallRoles())) {
  2089.                         $attrs['baseinstalldir'is_array($package$package[1$package;
  2090.                     }
  2091.                     if (isset($attrs['baseinstalldir'])) {
  2092.                         $name $attrs['baseinstalldir'. DIRECTORY_SEPARATOR . $name;
  2093.                     }
  2094.                 }
  2095.                 $pkgs[$name$this->checkFileMap($name$package$api$attrs);
  2096.                 if (PEAR::isError($pkgs[$name])) {
  2097.                     return $pkgs[$name];
  2098.                 }
  2099.             }
  2100.             return array_filter($pkgs$notempty);
  2101.         }
  2102.         if (empty($this->filemap_cache)) {
  2103.             if (PEAR::isError($e $this->_lock(LOCK_SH))) {
  2104.                 return $e;
  2105.             }
  2106.             $err $this->_readFileMap();
  2107.             $this->_unlock();
  2108.             if (PEAR::isError($err)) {
  2109.                 return $err;
  2110.             }
  2111.         }
  2112.         if (!$attrs{
  2113.             $attrs = array('role' => 'php')// any old call would be for PHP role only
  2114.         }
  2115.         if (isset($this->filemap_cache[$attrs['role']][$path])) {
  2116.             if ($api >= '1.1' && $this->filemap_cache[$attrs['role']][$path== $package{
  2117.                 return false;
  2118.             }
  2119.             return $this->filemap_cache[$attrs['role']][$path];
  2120.         }
  2121.         $l strlen($this->install_dir);
  2122.         if (substr($path0$l== $this->install_dir{
  2123.             $path preg_replace('!^'.DIRECTORY_SEPARATOR.'+!'''substr($path$l));
  2124.         }
  2125.         if (isset($this->filemap_cache[$attrs['role']][$path])) {
  2126.             if ($api >= '1.1' && $this->filemap_cache[$attrs['role']][$path== $package{
  2127.                 return false;
  2128.             }
  2129.             return $this->filemap_cache[$attrs['role']][$path];
  2130.         }
  2131.         return false;
  2132.     }
  2133.  
  2134.     // }}}
  2135.     // {{{ flush()
  2136.     /**
  2137.      * Force a reload of the filemap
  2138.      * @since 1.5.0RC3
  2139.      */
  2140.     function flushFileMap()
  2141.     {
  2142.         $this->filemap_cache = null;
  2143.         clearstatcache()// ensure that the next read gets the full, current filemap
  2144.     }
  2145.  
  2146.     // }}}
  2147.     // {{{ apiVersion()
  2148.     /**
  2149.      * Get the expected API version.  Channels API is version 1.1, as it is backwards
  2150.      * compatible with 1.0
  2151.      * @return string 
  2152.      */
  2153.     function apiVersion()
  2154.     {
  2155.         return '1.1';
  2156.     }
  2157.     // }}}
  2158.  
  2159.  
  2160.     /**
  2161.      * Parse a package name, or validate a parsed package name array
  2162.      * @param string|arraypass in an array of format
  2163.      *                      array(
  2164.      *                       'package' => 'pname',
  2165.      *                      ['channel' => 'channame',]
  2166.      *                      ['version' => 'version',]
  2167.      *                      ['state' => 'state',]
  2168.      *                      ['group' => 'groupname'])
  2169.      *                      or a string of format
  2170.      *                      [channel://][channame/]pname[-version|-state][/group=groupname]
  2171.      * @return array|PEAR_Error
  2172.      */
  2173.     function parsePackageName($param$defaultchannel 'pear.php.net')
  2174.     {
  2175.         $saveparam $param;
  2176.         if (is_array($param)) {
  2177.             // convert to string for error messages
  2178.             $saveparam $this->parsedPackageNameToString($param);
  2179.             // process the array
  2180.             if (!isset($param['package'])) {
  2181.                 return PEAR::raiseError('parsePackageName(): array $param ' .
  2182.                     'must contain a valid package name in index "param"',
  2183.                     'package'nullnull$param);
  2184.             }
  2185.             if (!isset($param['uri'])) {
  2186.                 if (!isset($param['channel'])) {
  2187.                     $param['channel'$defaultchannel;
  2188.                 }
  2189.             else {
  2190.                 $param['channel''__uri';
  2191.             }
  2192.         else {
  2193.             $components @parse_url((string) $param);
  2194.             if (isset($components['scheme'])) {
  2195.                 if ($components['scheme'== 'http'{
  2196.                     // uri package
  2197.                     $param = array('uri' => $param'channel' => '__uri');
  2198.                 elseif($components['scheme'!= 'channel'{
  2199.                     return PEAR::raiseError('parsePackageName(): only channel:// uris may ' .
  2200.                         'be downloaded, not "' $param '"''invalid'nullnull$param);
  2201.                 }
  2202.             }
  2203.             if (!isset($components['path'])) {
  2204.                 return PEAR::raiseError('parsePackageName(): array $param ' .
  2205.                     'must contain a valid package name in "' $param '"',
  2206.                     'package'nullnull$param);
  2207.             }
  2208.             if (isset($components['host'])) {
  2209.                 // remove the leading "/"
  2210.                 $components['path'substr($components['path']1);
  2211.             }
  2212.             if (!isset($components['scheme'])) {
  2213.                 if (strpos($components['path']'/'!== false{
  2214.                     if ($components['path']{0== '/'{
  2215.                         return PEAR::raiseError('parsePackageName(): this is not ' .
  2216.                             'a package name, it begins with "/" in "' $param '"',
  2217.                             'invalid'nullnull$param);
  2218.                     }
  2219.                     $parts explode('/'$components['path']);
  2220.                     $components['host'array_shift($parts);
  2221.                     if (count($parts> 1{
  2222.                         $components['path'array_pop($parts);
  2223.                         $components['host'.= '/' implode('/'$parts);
  2224.                     else {
  2225.                         $components['path'implode('/'$parts);
  2226.                     }
  2227.                 else {
  2228.                     $components['host'$defaultchannel;
  2229.                 }
  2230.             else {
  2231.                 if (strpos($components['path']'/')) {
  2232.                     $parts explode('/'$components['path']);
  2233.                     $components['path'array_pop($parts);
  2234.                     $components['host'.= '/' implode('/'$parts);
  2235.                 }
  2236.             }
  2237.  
  2238.             if (is_array($param)) {
  2239.                 $param['package'$components['path'];
  2240.             else {
  2241.                 $param = array(
  2242.                     'package' => $components['path']
  2243.                     );
  2244.                 if (isset($components['host'])) {
  2245.                     $param['channel'$components['host'];
  2246.                 }
  2247.             }
  2248.             if (isset($components['fragment'])) {
  2249.                 $param['group'$components['fragment'];
  2250.             }
  2251.             if (isset($components['user'])) {
  2252.                 $param['user'$components['user'];
  2253.             }
  2254.             if (isset($components['pass'])) {
  2255.                 $param['pass'$components['pass'];
  2256.             }
  2257.             if (isset($components['query'])) {
  2258.                 parse_str($components['query']$param['opts']);
  2259.             }
  2260.             // check for extension
  2261.             $pathinfo pathinfo($param['package']);
  2262.             if (isset($pathinfo['extension']&&
  2263.                   in_array(strtolower($pathinfo['extension'])array('tgz''tar'))) {
  2264.                 $param['extension'$pathinfo['extension'];
  2265.                 $param['package'substr($pathinfo['basename']0,
  2266.                     strlen($pathinfo['basename']- 4);
  2267.             }
  2268.             // check for version
  2269.             if (strpos($param['package']'-')) {
  2270.                 $test explode('-'$param['package']);
  2271.                 if (count($test!= 2{
  2272.                     return PEAR::raiseError('parsePackageName(): only one version/state ' .
  2273.                         'delimiter "-" is allowed in "' $saveparam '"',
  2274.                         'version'nullnull$param);
  2275.                 }
  2276.                 list($param['package']$param['version']$test;
  2277.             }
  2278.         }
  2279.         // validation
  2280.         $info $this->channelExists($param['channel']);
  2281.         if (PEAR::isError($info)) {
  2282.             return $info;
  2283.         }
  2284.         if (!$info{
  2285.             return PEAR::raiseError('unknown channel "' $param['channel'.
  2286.                 '" in "' $saveparam '"''channel'nullnull$param);
  2287.         }
  2288.         $chan $this->getChannel($param['channel']);
  2289.         if (PEAR::isError($chan)) {
  2290.             return $chan;
  2291.         }
  2292.         if (!$chan{
  2293.             return PEAR::raiseError("Exception: corrupt registry, could not " .
  2294.                 "retrieve channel " $param['channel'" information",
  2295.                 'registry'nullnull$param);
  2296.         }
  2297.         $param['channel'$chan->getName();
  2298.         $validate $chan->getValidationObject();
  2299.         $vpackage $chan->getValidationPackage();
  2300.         // validate package name
  2301.         if (!$validate->validPackageName($param['package']$vpackage['_content'])) {
  2302.             return PEAR::raiseError('parsePackageName(): invalid package name "' .
  2303.                 $param['package''" in "' $saveparam '"',
  2304.                 'package'nullnull$param);
  2305.         }
  2306.         if (isset($param['group'])) {
  2307.             if (!PEAR_Validate::validGroupName($param['group'])) {
  2308.                 return PEAR::raiseError('parsePackageName(): dependency group "' $param['group'.
  2309.                     '" is not a valid group name in "' $saveparam '"''group'nullnull,
  2310.                     $param);
  2311.             }
  2312.         }
  2313.         if (isset($param['state'])) {
  2314.             if (!in_array(strtolower($param['state'])$validate->getValidStates())) {
  2315.                 return PEAR::raiseError('parsePackageName(): state "' $param['state']
  2316.                     . '" is not a valid state in "' $saveparam '"',
  2317.                     'state'nullnull$param);
  2318.             }
  2319.         }
  2320.         if (isset($param['version'])) {
  2321.             if (isset($param['state'])) {
  2322.                 return PEAR::raiseError('parsePackageName(): cannot contain both ' .
  2323.                     'a version and a stability (state) in "' $saveparam '"',
  2324.                     'version/state'nullnull$param);
  2325.             }
  2326.             // check whether version is actually a state
  2327.             if (in_array(strtolower($param['version'])$validate->getValidStates())) {
  2328.                 $param['state'strtolower($param['version']);
  2329.                 unset($param['version']);
  2330.             else {
  2331.                 if (!$validate->validVersion($param['version'])) {
  2332.                     return PEAR::raiseError('parsePackageName(): "' $param['version'.
  2333.                         '" is neither a valid version nor a valid state in "' .
  2334.                         $saveparam '"''version/state'nullnull$param);
  2335.                 }
  2336.             }
  2337.         }
  2338.         return $param;
  2339.     }
  2340.  
  2341.     /**
  2342.      * @param array 
  2343.      * @return string 
  2344.      */
  2345.     function parsedPackageNameToString($parsed$brief = false)
  2346.     {
  2347.         if (is_string($parsed)) {
  2348.             return $parsed;
  2349.         }
  2350.         if (is_object($parsed)) {
  2351.             $p $parsed;
  2352.             $parsed = array(
  2353.                 'package' => $p->getPackage(),
  2354.                 'channel' => $p->getChannel(),
  2355.                 'version' => $p->getVersion(),
  2356.             );
  2357.         }
  2358.         if (isset($parsed['uri'])) {
  2359.             return $parsed['uri'];
  2360.         }
  2361.         if ($brief{
  2362.             if ($channel $this->channelAlias($parsed['channel'])) {
  2363.                 return $channel '/' $parsed['package'];
  2364.             }
  2365.         }
  2366.         $upass '';
  2367.         if (isset($parsed['user'])) {
  2368.             $upass $parsed['user'];
  2369.             if (isset($parsed['pass'])) {
  2370.                 $upass .= ':' $parsed['pass'];
  2371.             }
  2372.             $upass = "$upass@";
  2373.         }
  2374.         $ret 'channel://' $upass $parsed['channel''/' $parsed['package'];
  2375.         if (isset($parsed['version']|| isset($parsed['state'])) {
  2376.             $ver = isset($parsed['version']$parsed['version''';
  2377.             $ver .= isset($parsed['state']$parsed['state''';
  2378.             $ret .= '-' $ver;
  2379.         }
  2380.         if (isset($parsed['extension'])) {
  2381.             $ret .= '.' $parsed['extension'];
  2382.         }
  2383.         if (isset($parsed['opts'])) {
  2384.             $ret .= '?';
  2385.             foreach ($parsed['opts'as $name => $value{
  2386.                 $parsed['opts'][$name= "$name=$value";
  2387.             }
  2388.             $ret .= implode('&'$parsed['opts']);
  2389.         }
  2390.         if (isset($parsed['group'])) {
  2391.             $ret .= '#' $parsed['group'];
  2392.         }
  2393.         return $ret;
  2394.     }
  2395. }

Documentation generated on Wed, 06 Jul 2011 23:31:13 +0000 by phpDocumentor 1.4.3. PEAR Logo Copyright © PHP Group 2004.