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 2004/01/08 17:33:12 sniper 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.1---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.1---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.             $this->lock_fp = @fopen($this->lockfile, $open_mode);
  284.  
  285.             if (!is_resource($this->lock_fp)) {
  286.                 return $this->raiseError("could not create lock file" .
  287.                                          (isset($php_errormsg) ? ": " . $php_errormsg : ""));
  288.             }
  289.             if (!(int)flock($this->lock_fp, $mode)) {
  290.                 switch ($mode) {
  291.                     case LOCK_SH: $str = 'shared';    break;
  292.                     case LOCK_EX: $str = 'exclusive'; break;
  293.                     case LOCK_UN: $str = 'unlock';    break;
  294.                     default:      $str = 'unknown';   break;
  295.                 }
  296.                 return $this->raiseError("could not acquire $str lock ($this->lockfile)",
  297.                                          PEAR_REGISTRY_ERROR_LOCK);
  298.             }
  299.         }
  300.         return true;
  301.     }
  302.  
  303.     // }}}
  304.     // {{{ _unlock()
  305.     function _unlock()
  306.     {
  307.         $ret = $this->_lock(LOCK_UN);
  308.         $this->lock_fp = null;
  309.         return $ret;
  310.     }
  311.  
  312.     // }}}
  313.     // {{{ _packageExists()
  314.     function _packageExists($package)
  315.     {
  316.         return file_exists($this->_packageFileName($package));
  317.     }
  318.  
  319.     // }}}
  320.     // {{{ _packageInfo()
  321.     function _packageInfo($package = null, $key = null)
  322.     {
  323.         if ($package === null) {
  324.             return array_map(array($this, '_packageInfo'),
  325.                              $this->_listPackages());
  326.         }
  327.         $fp = $this->_openPackageFile($package, 'r');
  328.         if ($fp === null) {
  329.             return null;
  330.         }
  331.         $rt = get_magic_quotes_runtime();
  332.         set_magic_quotes_runtime(0);
  333.         $data = fread($fp, filesize($this->_packageFileName($package)));
  334.         set_magic_quotes_runtime($rt);
  335.         $this->_closePackageFile($fp);
  336.         $data = unserialize($data);
  337.         if ($key === null) {
  338.             return $data;
  339.         }
  340.         if (isset($data[$key])) {
  341.             return $data[$key];
  342.         }
  343.         return null;
  344.     }
  345.  
  346.     // }}}
  347.     // {{{ _listPackages()
  348.     function _listPackages()
  349.     {
  350.         $pkglist = array();
  351.         $dp = @opendir($this->statedir);
  352.         if (!$dp) {
  353.             return $pkglist;
  354.         }
  355.         while ($ent = readdir($dp)) {
  356.             if ($ent{0} == '.' || substr($ent, -4) != '.reg') {
  357.                 continue;
  358.             }
  359.             $pkglist[] = substr($ent, 0, -4);
  360.         }
  361.         return $pkglist;
  362.     }
  363.  
  364.     // }}}
  365.     // {{{ packageExists()
  366.     function packageExists($package)
  367.     {
  368.         if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  369.             return $e;
  370.         }
  371.         $ret = $this->_packageExists($package);
  372.         $this->_unlock();
  373.         return $ret;
  374.     }
  375.  
  376.     // }}}
  377.     // {{{ packageInfo()
  378.     function packageInfo($package = null, $key = null)
  379.     {
  380.         if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  381.             return $e;
  382.         }
  383.         $ret = $this->_packageInfo($package, $key);
  384.         $this->_unlock();
  385.         return $ret;
  386.     }
  387.  
  388.     // }}}
  389.     // {{{ listPackages()
  390.     function listPackages()
  391.     {
  392.         if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  393.             return $e;
  394.         }
  395.         $ret = $this->_listPackages();
  396.         $this->_unlock();
  397.         return $ret;
  398.     }
  399.  
  400.     // }}}
  401.     // {{{ addPackage()
  402.     function addPackage($package, $info)
  403.     {
  404.         if ($this->packageExists($package)) {
  405.             return false;
  406.         }
  407.         if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
  408.             return $e;
  409.         }
  410.         $fp = $this->_openPackageFile($package, 'wb');
  411.         if ($fp === null) {
  412.             $this->_unlock();
  413.             return false;
  414.         }
  415.         $info['_lastmodified'] = time();
  416.         fwrite($fp, serialize($info));
  417.         $this->_closePackageFile($fp);
  418.         $this->_unlock();
  419.         return true;
  420.     }
  421.  
  422.     // }}}
  423.     // {{{ deletePackage()
  424.     function deletePackage($package)
  425.     {
  426.         if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
  427.             return $e;
  428.         }
  429.         $file = $this->_packageFileName($package);
  430.         $ret = @unlink($file);
  431.         $this->rebuildFileMap();
  432.         $this->_unlock();
  433.         return $ret;
  434.     }
  435.  
  436.     // }}}
  437.     // {{{ updatePackage()
  438.     function updatePackage($package, $info, $merge = true)
  439.     {
  440.         $oldinfo = $this->packageInfo($package);
  441.         if (empty($oldinfo)) {
  442.             return false;
  443.         }
  444.         if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
  445.             return $e;
  446.         }
  447.         $fp = $this->_openPackageFile($package, 'w');
  448.         if ($fp === null) {
  449.             $this->_unlock();
  450.             return false;
  451.         }
  452.         $info['_lastmodified'] = time();
  453.         if ($merge) {
  454.             fwrite($fp, serialize(array_merge($oldinfo, $info)));
  455.         } else {
  456.             fwrite($fp, serialize($info));
  457.         }
  458.         $this->_closePackageFile($fp);
  459.         if (isset($info['filelist'])) {
  460.             $this->rebuildFileMap();
  461.         }
  462.         $this->_unlock();
  463.         return true;
  464.     }
  465.  
  466.     // }}}
  467.     // {{{ checkFileMap()
  468.     /**
  469.      * Test whether a file belongs to a package.
  470.      *
  471.      * @param string $path file path, absolute or relative to the pear
  472.      * install dir
  473.      *
  474.      * @return string which package the file belongs to, or an empty
  475.      * string if the file does not belong to an installed package
  476.      *
  477.      * @access public
  478.      */
  479.     function checkFileMap($path)
  480.     {
  481.         if (is_array($path)) {
  482.             static $notempty;
  483.             if (empty($notempty)) {
  484.                 $notempty = create_function('$a','return !empty($a);');
  485.             }
  486.             $pkgs = array();
  487.             foreach ($path as $name => $attrs) {
  488.                 if (is_array($attrs) && isset($attrs['baseinstalldir'])) {
  489.                     $name = $attrs['baseinstalldir'].DIRECTORY_SEPARATOR.$name;
  490.                 }
  491.                 $pkgs[$name] = $this->checkFileMap($name);
  492.             }
  493.             return array_filter($pkgs, $notempty);
  494.         }
  495.         if (empty($this->filemap_cache) && PEAR::isError($this->readFileMap())) {
  496.             return $err;
  497.         }
  498.         if (isset($this->filemap_cache[$path])) {
  499.             return $this->filemap_cache[$path];
  500.         }
  501.         $l = strlen($this->install_dir);
  502.         if (substr($path, 0, $l) == $this->install_dir) {
  503.             $path = preg_replace('!^'.DIRECTORY_SEPARATOR.'+!', '', substr($path, $l));
  504.         }
  505.         if (isset($this->filemap_cache[$path])) {
  506.             return $this->filemap_cache[$path];
  507.         }
  508.         return '';
  509.     }
  510.  
  511.     // }}}
  512. }
  513.  

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