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

Source for file Registry.php

Documentation is available at Registry.php

  1. <?php
  2. //
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 5                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2004 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 3.0 of the PHP license,       |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available through the world-wide-web at the following url:           |
  11. // | http://www.php.net/license/3_0.txt.                                  |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Author: Stig Bakken <ssb@php.net>                                    |
  17. // |         Tomas V.V.Cox <cox@idecnet.com>                              |
  18. // |                                                                      |
  19. // +----------------------------------------------------------------------+
  20. //
  21. // $Id: Registry.php,v 1.50.4.3 2004/10/26 19:19:56 cellog Exp $
  22.  
  23. /*
  24. TODO:
  25.     - Transform into singleton()
  26.     - Add application level lock (avoid change the registry from the cmdline
  27.       while using the GTK interface, for ex.)
  28. */
  29. require_once "System.php";
  30. require_once "PEAR.php";
  31.  
  32. define('PEAR_REGISTRY_ERROR_LOCK',   -2);
  33. define('PEAR_REGISTRY_ERROR_FORMAT'-3);
  34. define('PEAR_REGISTRY_ERROR_FILE',   -4);
  35.  
  36. /**
  37.  * Administration class used to maintain the installed package database.
  38.  */
  39. class PEAR_Registry extends PEAR
  40. {
  41.     // {{{ properties
  42.  
  43.     /** Directory where registry files are stored.
  44.      * @var string 
  45.      */
  46.     var $statedir '';
  47.  
  48.     /** File where the file map is stored
  49.      * @var string 
  50.      */
  51.     var $filemap '';
  52.  
  53.     /** Name of file used for locking the registry
  54.      * @var string 
  55.      */
  56.     var $lockfile '';
  57.  
  58.     /** File descriptor used during locking
  59.      * @var resource 
  60.      */
  61.     var $lock_fp = null;
  62.  
  63.     /** Mode used during locking
  64.      * @var int 
  65.      */
  66.     var $lock_mode = 0; // XXX UNUSED
  67.  
  68.     /** Cache of package information.  Structure:
  69.      * array(
  70.      *   'package' => array('id' => ... ),
  71.      *   ... )
  72.      * @var array 
  73.      */
  74.     var $pkginfo_cache = array();
  75.  
  76.     /** Cache of file map.  Structure:
  77.      * array( '/path/to/file' => 'package', ... )
  78.      * @var array 
  79.      */
  80.     var $filemap_cache = array();
  81.  
  82.     // }}}
  83.  
  84.     // {{{ constructor
  85.  
  86.     /**
  87.      * PEAR_Registry constructor.
  88.      *
  89.      * @param string (optional) PEAR install directory (for .php files)
  90.      *
  91.      * @access public
  92.      */
  93.     function PEAR_Registry($pear_install_dir = PEAR_INSTALL_DIR)
  94.     {
  95.         parent::PEAR();
  96.         $ds = DIRECTORY_SEPARATOR;
  97.         $this->install_dir $pear_install_dir;
  98.         $this->statedir $pear_install_dir.$ds.'.registry';
  99.         $this->filemap  $pear_install_dir.$ds.'.filemap';
  100.         $this->lockfile $pear_install_dir.$ds.'.lock';
  101.  
  102.         // XXX Compatibility code should be removed in the future
  103.         // rename all registry files if any to lowercase
  104.         if (!OS_WINDOWS && $handle @opendir($this->statedir)) {
  105.             $dest $this->statedir . DIRECTORY_SEPARATOR;
  106.             while (false !== ($file readdir($handle))) {
  107.                 if (preg_match('/^.*[A-Z].*\.reg$/'$file)) {
  108.                     rename($dest $file$dest strtolower($file));
  109.                 }
  110.             }
  111.             closedir($handle);
  112.         }
  113.         if (!file_exists($this->filemap)) {
  114.             $this->rebuildFileMap();
  115.         }
  116.     }
  117.  
  118.     // }}}
  119.     // {{{ destructor
  120.  
  121.     /**
  122.      * PEAR_Registry destructor.  Makes sure no locks are forgotten.
  123.      *
  124.      * @access private
  125.      */
  126.     function _PEAR_Registry()
  127.     {
  128.         parent::_PEAR();
  129.         if (is_resource($this->lock_fp)) {
  130.             $this->_unlock();
  131.         }
  132.     }
  133.  
  134.     // }}}
  135.  
  136.     // {{{ _assertStateDir()
  137.  
  138.     /**
  139.      * Make sure the directory where we keep registry files exists.
  140.      *
  141.      * @return bool TRUE if directory exists, FALSE if it could not be
  142.      *  created
  143.      *
  144.      * @access private
  145.      */
  146.     function _assertStateDir()
  147.     {
  148.         if (!@is_dir($this->statedir)) {
  149.             if (!System::mkdir(array('-p'$this->statedir))) {
  150.                 return $this->raiseError("could not create directory '{$this->statedir}'");
  151.             }
  152.         }
  153.         return true;
  154.     }
  155.  
  156.     // }}}
  157.     // {{{ _packageFileName()
  158.     /**
  159.      * Get the name of the file where data for a given package is stored.
  160.      *
  161.      * @param string package name
  162.      *
  163.      * @return string registry file name
  164.      *
  165.      * @access public
  166.      */
  167.     function _packageFileName($package)
  168.     {
  169.         return $this->statedir . DIRECTORY_SEPARATOR . strtolower($package) . '.reg';
  170.     }
  171.  
  172.     // }}}
  173.     // {{{ _openPackageFile()
  174.     function _openPackageFile($package, $mode)
  175.     {
  176.         $this->_assertStateDir();
  177.         $file = $this->_packageFileName($package);
  178.         $fp = @fopen($file, $mode);
  179.         if (!$fp) {
  180.             return null;
  181.         }
  182.         return $fp;
  183.     }
  184.  
  185.     // }}}
  186.     // {{{ _closePackageFile()
  187.     function _closePackageFile($fp)
  188.     {
  189.         fclose($fp);
  190.     }
  191.  
  192.     // }}}
  193.     // {{{ rebuildFileMap()
  194.     function rebuildFileMap()
  195.     {
  196.         $packages = $this->listPackages();
  197.         $files = array();
  198.         foreach ($packages as $package) {
  199.             $version = $this->packageInfo($package, 'version');
  200.             $filelist = $this->packageInfo($package, 'filelist');
  201.             if (!is_array($filelist)) {
  202.                 continue;
  203.             }
  204.             foreach ($filelist as $name => $attrs) {
  205.                 if (isset($attrs['role']) && $attrs['role'] != 'php') {
  206.                     continue;
  207.                 }
  208.                 if (isset($attrs['baseinstalldir'])) {
  209.                     $file = $attrs['baseinstalldir'].DIRECTORY_SEPARATOR.$name;
  210.                 } else {
  211.                     $file = $name;
  212.                 }
  213.                 $file = preg_replace(',^/+,', '', $file);
  214.                 $files[$file] = $package;
  215.             }
  216.         }
  217.         $this->_assertStateDir();
  218.         $fp = @fopen($this->filemap, 'wb');
  219.         if (!$fp) {
  220.             return false;
  221.         }
  222.         $this->filemap_cache = $files;
  223.         fwrite($fp, serialize($files));
  224.         fclose($fp);
  225.         return true;
  226.     }
  227.  
  228.     // }}}
  229.     // {{{ readFileMap()
  230.     function readFileMap()
  231.     {
  232.         $fp = @fopen($this->filemap, 'r');
  233.         if (!$fp) {
  234.             return $this->raiseError('PEAR_Registry: could not open filemap', <a href="../PEAR/_PEAR-1.3.5---PEAR---Registry.php.html#definePEAR_REGISTRY_ERROR_FILE">PEAR_REGISTRY_ERROR_FILE</a>, null, null, $php_errormsg);
  235.         }
  236.         $fsize = filesize($this->filemap);
  237.         $rt = get_magic_quotes_runtime();
  238.         set_magic_quotes_runtime(0);
  239.         $data = fread($fp, $fsize);
  240.         set_magic_quotes_runtime($rt);
  241.         fclose($fp);
  242.         $tmp = unserialize($data);
  243.         if (!$tmp && $fsize > 7) {
  244.             return $this->raiseError('PEAR_Registry: invalid filemap data', <a href="../PEAR/_PEAR-1.3.5---PEAR---Registry.php.html#definePEAR_REGISTRY_ERROR_FORMAT">PEAR_REGISTRY_ERROR_FORMAT</a>, null, null, $data);
  245.         }
  246.         $this->filemap_cache = $tmp;
  247.         return true;
  248.     }
  249.  
  250.     // }}}
  251.     // {{{ _lock()
  252.     /**
  253.      * Lock the registry.
  254.      *
  255.      * @param integer lock mode, one of LOCK_EX, LOCK_SH or LOCK_UN.
  256.      *                See flock manual for more information.
  257.      *
  258.      * @return bool TRUE on success, FALSE if locking failed, or a
  259.      *              PEAR error if some other error occurs (such as the
  260.      *              lock file not being writable).
  261.      *
  262.      * @access private
  263.      */
  264.     function _lock($mode = LOCK_EX)
  265.     {
  266.         if (!eregi('Windows 9', php_uname())) {
  267.             if ($mode != LOCK_UN && is_resource($this->lock_fp)) {
  268.                 // XXX does not check type of lock (LOCK_SH/LOCK_EX)
  269.                 return true;
  270.             }
  271.             if (PEAR::isError($err = $this->_assertStateDir())) {
  272.                 return $err;
  273.             }
  274.             $open_mode = 'w';
  275.             // XXX People reported problems with LOCK_SH and 'w'
  276.             if ($mode === LOCK_SH || $mode === LOCK_UN) {
  277.                 if (@!is_file($this->lockfile)) {
  278.                     touch($this->lockfile);
  279.                 }
  280.                 $open_mode = 'r';
  281.             }
  282.  
  283.             if (!is_resource($this->lock_fp)) {
  284.                 $this->lock_fp = @fopen($this->lockfile, $open_mode);
  285.             }
  286.  
  287.             if (!is_resource($this->lock_fp)) {
  288.                 return $this->raiseError("could not create lock file" .
  289.                                          (isset($php_errormsg) ? ": " . $php_errormsg : ""));
  290.             }
  291.             if (!(int)flock($this->lock_fp, $mode)) {
  292.                 switch ($mode) {
  293.                     case LOCK_SH: $str = 'shared';    break;
  294.                     case LOCK_EX: $str = 'exclusive'; break;
  295.                     case LOCK_UN: $str = 'unlock';    break;
  296.                     default:      $str = 'unknown';   break;
  297.                 }
  298.                 return $this->raiseError("could not acquire $str lock ($this->lockfile)",
  299.                                          PEAR_REGISTRY_ERROR_LOCK);
  300.             }
  301.         }
  302.         return true;
  303.     }
  304.  
  305.     // }}}
  306.     // {{{ _unlock()
  307.     function _unlock()
  308.     {
  309.         $ret = $this->_lock(LOCK_UN);
  310.         if (is_resource($this->lock_fp)) {
  311.             fclose($this->lock_fp);
  312.         }
  313.         $this->lock_fp = null;
  314.         return $ret;
  315.     }
  316.  
  317.     // }}}
  318.     // {{{ _packageExists()
  319.     function _packageExists($package)
  320.     {
  321.         return file_exists($this->_packageFileName($package));
  322.     }
  323.  
  324.     // }}}
  325.     // {{{ _packageInfo()
  326.     function _packageInfo($package = null, $key = null)
  327.     {
  328.         if ($package === null) {
  329.             return array_map(array($this, '_packageInfo'),
  330.                              $this->_listPackages());
  331.         }
  332.         $fp = $this->_openPackageFile($package, 'r');
  333.         if ($fp === null) {
  334.             return null;
  335.         }
  336.         $rt = get_magic_quotes_runtime();
  337.         set_magic_quotes_runtime(0);
  338.         $data = fread($fp, filesize($this->_packageFileName($package)));
  339.         set_magic_quotes_runtime($rt);
  340.         $this->_closePackageFile($fp);
  341.         $data = unserialize($data);
  342.         if ($key === null) {
  343.             return $data;
  344.         }
  345.         if (isset($data[$key])) {
  346.             return $data[$key];
  347.         }
  348.         return null;
  349.     }
  350.  
  351.     // }}}
  352.     // {{{ _listPackages()
  353.     function _listPackages()
  354.     {
  355.         $pkglist = array();
  356.         $dp = @opendir($this->statedir);
  357.         if (!$dp) {
  358.             return $pkglist;
  359.         }
  360.         while ($ent = readdir($dp)) {
  361.             if ($ent{0} == '.' || substr($ent, -4) != '.reg') {
  362.                 continue;
  363.             }
  364.             $pkglist[] = substr($ent, 0, -4);
  365.         }
  366.         return $pkglist;
  367.     }
  368.  
  369.     // }}}
  370.     // {{{ packageExists()
  371.     function packageExists($package)
  372.     {
  373.         if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  374.             return $e;
  375.         }
  376.         $ret = $this->_packageExists($package);
  377.         $this->_unlock();
  378.         return $ret;
  379.     }
  380.  
  381.     // }}}
  382.     // {{{ packageInfo()
  383.     function packageInfo($package = null, $key = null)
  384.     {
  385.         if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  386.             return $e;
  387.         }
  388.         $ret = $this->_packageInfo($package, $key);
  389.         $this->_unlock();
  390.         return $ret;
  391.     }
  392.  
  393.     // }}}
  394.     // {{{ listPackages()
  395.     function listPackages()
  396.     {
  397.         if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  398.             return $e;
  399.         }
  400.         $ret = $this->_listPackages();
  401.         $this->_unlock();
  402.         return $ret;
  403.     }
  404.  
  405.     // }}}
  406.     // {{{ addPackage()
  407.     function addPackage($package, $info)
  408.     {
  409.         if ($this->packageExists($package)) {
  410.             return false;
  411.         }
  412.         if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
  413.             return $e;
  414.         }
  415.         $fp = $this->_openPackageFile($package, 'wb');
  416.         if ($fp === null) {
  417.             $this->_unlock();
  418.             return false;
  419.         }
  420.         $info['_lastmodified'] = time();
  421.         fwrite($fp, serialize($info));
  422.         $this->_closePackageFile($fp);
  423.         $this->_unlock();
  424.         return true;
  425.     }
  426.  
  427.     // }}}
  428.     // {{{ deletePackage()
  429.     function deletePackage($package)
  430.     {
  431.         if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
  432.             return $e;
  433.         }
  434.         $file = $this->_packageFileName($package);
  435.         $ret = @unlink($file);
  436.         $this->rebuildFileMap();
  437.         $this->_unlock();
  438.         return $ret;
  439.     }
  440.  
  441.     // }}}
  442.     // {{{ updatePackage()
  443.     function updatePackage($package, $info, $merge = true)
  444.     {
  445.         $oldinfo = $this->packageInfo($package);
  446.         if (empty($oldinfo)) {
  447.             return false;
  448.         }
  449.         if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
  450.             return $e;
  451.         }
  452.         $fp = $this->_openPackageFile($package, 'w');
  453.         if ($fp === null) {
  454.             $this->_unlock();
  455.             return false;
  456.         }
  457.         $info['_lastmodified'] = time();
  458.         if ($merge) {
  459.             fwrite($fp, serialize(array_merge($oldinfo, $info)));
  460.         } else {
  461.             fwrite($fp, serialize($info));
  462.         }
  463.         $this->_closePackageFile($fp);
  464.         if (isset($info['filelist'])) {
  465.             $this->rebuildFileMap();
  466.         }
  467.         $this->_unlock();
  468.         return true;
  469.     }
  470.  
  471.     // }}}
  472.     // {{{ checkFileMap()
  473.     /**
  474.      * Test whether a file belongs to a package.
  475.      *
  476.      * @param string $path file path, absolute or relative to the pear
  477.      * install dir
  478.      *
  479.      * @return string which package the file belongs to, or an empty
  480.      * string if the file does not belong to an installed package
  481.      *
  482.      * @access public
  483.      */
  484.     function checkFileMap($path)
  485.     {
  486.         if (is_array($path)) {
  487.             static $notempty;
  488.             if (empty($notempty)) {
  489.                 $notempty = create_function('$a','return !empty($a);');
  490.             }
  491.             $pkgs = array();
  492.             foreach ($path as $name => $attrs) {
  493.                 if (is_array($attrs) && isset($attrs['baseinstalldir'])) {
  494.                     $name = $attrs['baseinstalldir'].DIRECTORY_SEPARATOR.$name;
  495.                 }
  496.                 $pkgs[$name] = $this->checkFileMap($name);
  497.             }
  498.             return array_filter($pkgs, $notempty);
  499.         }
  500.         if (empty($this->filemap_cache) && PEAR::isError($this->readFileMap())) {
  501.             return $err;
  502.         }
  503.         if (isset($this->filemap_cache[$path])) {
  504.             return $this->filemap_cache[$path];
  505.         }
  506.         $l = strlen($this->install_dir);
  507.         if (substr($path, 0, $l) == $this->install_dir) {
  508.             $path = preg_replace('!^'.DIRECTORY_SEPARATOR.'+!', '', substr($path, $l));
  509.         }
  510.         if (isset($this->filemap_cache[$path])) {
  511.             return $this->filemap_cache[$path];
  512.         }
  513.         return '';
  514.     }
  515.  
  516.     // }}}
  517. }
  518.  

Documentation generated on Mon, 11 Mar 2019 14:24:00 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.