home *** CD-ROM | disk | FTP | other *** search
/ Enter 2004 June / ENTER.ISO / files / xampp-win32-1.4.5-installer.exe / xampp / File.php < prev    next >
Encoding:
PHP Script  |  2004-03-24  |  15.8 KB  |  413 lines

  1. <?php
  2. //
  3. // +------------------------------------------------------------------------+
  4. // | PEAR :: Package File Manager                                           |
  5. // +------------------------------------------------------------------------+
  6. // | Copyright (c) 2003-2004 Gregory Beaver                                 |
  7. // | Email         cellog@phpdoc.org                                        |
  8. // +------------------------------------------------------------------------+
  9. // | This source file is subject to version 3.00 of the PHP License,        |
  10. // | that is available at http://www.php.net/license/3_0.txt.               |
  11. // | If you did not receive a copy of the PHP license and are unable to     |
  12. // | obtain it through the world-wide-web, please send a note to            |
  13. // | license@php.net so we can mail you a copy immediately.                 |
  14. // +------------------------------------------------------------------------+
  15. // | Portions of this code based on phpDocumentor                           |
  16. // | Web           http://www.phpdoc.org                                    |
  17. // | Mirror        http://phpdocu.sourceforge.net/                          |
  18. // +------------------------------------------------------------------------+
  19. // $Id: File.php,v 1.17 2004/02/07 06:33:31 cellog Exp $
  20. //
  21. /**
  22.  * Retrieve the files from a directory listing
  23.  * @package PEAR_PackageFileManager
  24.  */
  25. /**
  26.  * Retrieve the files from a directory listing
  27.  *
  28.  * This class is used to retrieve a raw directory
  29.  * listing.  Use the {@link PEAR_PackageFileManager_CVS}
  30.  * class to only retrieve the contents of a cvs
  31.  * repository when generating the package.xml
  32.  * @package PEAR_PackageFileManager
  33.  */
  34. class PEAR_PackageFileManager_File {
  35.     /**
  36.      * @var array
  37.      * @access private
  38.      */
  39.     var $_options = 
  40.             array(
  41.                  );
  42.  
  43.     /**
  44.      * @access private
  45.      * @var PEAR_PackageFileManager
  46.      */
  47.     var $_parent;
  48.  
  49.     /**
  50.      * @access private
  51.      * @var array|false
  52.      */
  53.     var $_ignore = false;
  54.  
  55.     /**
  56.      * Set up the File filelist generator
  57.      *
  58.      * 'ignore' and 'include' are the only options that this class uses.  See
  59.      * {@link PEAR_PackageFileManager::setOptions()} for
  60.      * more information and formatting of this option
  61.      * @param PEAR_PackageFileManager
  62.      * @param array
  63.      */
  64.     function PEAR_PackageFileManager_File(&$parent, $options)
  65.     {
  66.         $this->_parent = &$parent;
  67.         $this->_options = array_merge($this->_options, $options);
  68.     }
  69.     
  70.     /**
  71.      * Generate the <filelist></filelist> section
  72.      * of the package file.
  73.      *
  74.      * This function performs the backend generation of the array
  75.      * containing all files in this package
  76.      * @return array
  77.      */
  78.     function getFileList()
  79.     {
  80.         $package_directory = $this->_options['packagedirectory'];
  81.         $ignore = $this->_options['ignore'];
  82.         // implicitly ignore packagefile
  83.         $ignore[] = $this->_options['packagefile'];
  84.         $include = $this->_options['include'];
  85.         $this->ignore = array(false, false);
  86.         $this->_setupIgnore($ignore, 1);
  87.         $this->_setupIgnore($include, 0);
  88.         $allfiles = $this->dirList(substr($package_directory, 0, strlen($package_directory) - 1));
  89.         if (PEAR::isError($allfiles)) {
  90.             return $allfiles;
  91.         }
  92.         if (!count($allfiles)) {
  93.             return PEAR_PackageFileManager::raiseError(PEAR_PACKAGEFILEMANAGER_NO_FILES,
  94.                 substr($package_directory, 0, strlen($package_directory) - 1));
  95.         }
  96.         $struc = array();
  97.         foreach($allfiles as $file) {
  98.             $path = substr(dirname($file), strlen(str_replace(DIRECTORY_SEPARATOR, 
  99.                                                               '/',
  100.                                                               realpath($package_directory))) + 1);
  101.             if (!$path) {
  102.                 $path = '/';
  103.             }
  104.             $ext = array_pop(explode('.', $file));
  105.             if (strlen($ext) == strlen($file)) {
  106.                 $ext = '';
  107.             }
  108.             $struc[$path][] = array('file' => basename($file),
  109.                                     'ext' => $ext,
  110.                                     'path' => (($path == '/') ? basename($file) : $path . '/' . basename($file)),
  111.                                     'fullpath' => $file);
  112.         }
  113.         if (!count($struc)) {
  114.             $newig = implode($this->_options['ignore'], ', ');
  115.             return PEAR_PackageFileManager::raiseError(PEAR_PACKAGEFILEMANAGER_IGNORED_EVERYTHING,
  116.                 substr($package_directory, 0, strlen($package_directory) - 1), $newig);
  117.         }
  118.         uksort($struc,'strnatcasecmp');
  119.         foreach($struc as $key => $ind) {
  120.             usort($ind, array($this, 'sortfiles'));
  121.             $struc[$key] = $ind;
  122.         }
  123.  
  124.         $tempstruc = $struc;
  125.         $struc = array('/' => $tempstruc['/']);
  126.         $bv = 0;
  127.         foreach($tempstruc as $key => $ind) {
  128.             $save = $key;
  129.             if ($key != '/')
  130.             {
  131.                 $struc['/'] = $this->_setupDirs($struc['/'], explode('/',$key), $tempstruc[$key]);
  132.             }
  133.         }
  134.         uksort($struc['/'], array($this, 'mystrucsort'));
  135.  
  136.         return $struc;
  137.     }
  138.     
  139.     /**
  140.      * Retrieve a listing of every file in $directory and
  141.      * all subdirectories.
  142.      *
  143.      * The return format is an array of full paths to files
  144.      * @access protected
  145.      * @return array list of files in a directory
  146.      * @param string $directory full path to the directory you want the list of
  147.      * @throws PEAR_PACKAGEFILEMANAGER_DIR_DOESNT_EXIST
  148.      */
  149.     function dirList($directory)
  150.     {
  151.         $ret = false;
  152.         if (@is_dir($directory)) {
  153.             $ret = array();
  154.             $d = @dir($directory); // thanks to Jason E Sweat (jsweat@users.sourceforge.net) for fix
  155.             while($d && $entry=$d->read()) {
  156.                 if ($this->_testFile($directory, $entry)) {
  157.                     if (is_file($directory . '/' . $entry)) {
  158.                         // if include option was set, then only pass included files
  159.                         if ($this->ignore[0]) {
  160.                             if ($this->_checkIgnore($entry, $directory . '/' . $entry, 0)) {
  161.                                 continue;
  162.                             }
  163.                         }
  164.                         // if ignore option was set, then only pass included files
  165.                         if ($this->ignore[1]) {
  166.                             if ($this->_checkIgnore($entry, $directory . '/' . $entry, 1)) {
  167.                                 continue;
  168.                             }
  169.                         }
  170.                         $ret[] = $directory . '/' . $entry;
  171.                     }
  172.                     if (is_dir($directory . '/' . $entry)) {
  173.                         $tmp = $this->dirList($directory . '/' . $entry);
  174.                         if (is_array($tmp)) {
  175.                             foreach($tmp as $ent) {
  176.                                 $ret[] = $ent;
  177.                             }
  178.                         }
  179.                     }
  180.                 }
  181.             }
  182.             if ($d) {
  183.                 $d->close();
  184.             }
  185.         } else {
  186.             return PEAR_PackageFileManager::raiseError(PEAR_PACKAGEFILEMANAGER_DIR_DOESNT_EXIST, $directory);
  187.         }
  188.         return $ret;
  189.     }
  190.     
  191.     /**
  192.      * Test whether an entry should be processed.
  193.      * 
  194.      * Normally, it ignores all files and directories that begin with "."  addhiddenfiles option
  195.      * instead only ignores "." and ".." entries
  196.      * @access private
  197.      * @param string directory name of entry
  198.      * @param string name
  199.      */
  200.     function _testFile($directory, $entry)
  201.     {
  202.         if ($this->_options['addhiddenfiles']) {
  203.             return is_file($directory . '/' . $entry) || (is_dir($directory . '/' . $entry) && !in_array($entry, array('.', '..')));
  204.         } else {
  205.             return $entry{0} != '.';
  206.         }
  207.     }
  208.  
  209.     /**
  210.      * Tell whether to ignore a file or a directory
  211.      * allows * and ? wildcards
  212.      *
  213.      * @param    string  $file    just the file name of the file or directory,
  214.      *                          in the case of directories this is the last dir
  215.      * @param    string  $path    the full path
  216.      * @param    1|0    $return  value to return if regexp matches.  Set this to
  217.      *                            false to include only matches, true to exclude
  218.      *                            all matches
  219.      * @return   bool    true if $path should be ignored, false if it should not
  220.      * @access private
  221.      */
  222.     function _checkIgnore($file, $path, $return = 1)
  223.     {
  224.         $path = realpath($path);
  225.         if (is_array($this->ignore[$return])) {
  226.             foreach($this->ignore[$return] as $match) {
  227.                 // match is an array if the ignore parameter was a /path/to/pattern
  228.                 if (is_array($match)) {
  229.                     // check to see if the path matches with a path delimiter appended
  230.                     preg_match('/^' . strtoupper($match[0]).'$/', strtoupper($path) . '/',$find);
  231.                     if (!count($find)) {
  232.                         // check to see if it matches without an appended path delimiter
  233.                         preg_match('/^' . strtoupper($match[0]).'$/', strtoupper($path), $find);
  234.                     }
  235.                     if (count($find)) {
  236.                         // check to see if the file matches the file portion of the regex string
  237.                         preg_match('/^' . strtoupper($match[1]).'$/', strtoupper($file), $find);
  238.                         if (count($find)) {
  239.                             return $return;
  240.                         }
  241.                     }
  242.                     // check to see if the full path matches the regex
  243.                     preg_match('/^' . strtoupper($match[0]).'$/',
  244.                                strtoupper($path . DIRECTORY_SEPARATOR . $file), $find);
  245.                     if (count($find)) {
  246.                         return $return;
  247.                     }
  248.                 } else {
  249.                     // ignore parameter was just a pattern with no path delimiters
  250.                     // check it against the path
  251.                     preg_match('/^' . strtoupper($match).'$/', strtoupper($path), $find);
  252.                     if (count($find)) {
  253.                         return $return;
  254.                     }
  255.                     // check it against the file only
  256.                     preg_match('/^' . strtoupper($match).'$/', strtoupper($file), $find);
  257.                     if (count($find)) {
  258.                         return $return;
  259.                     }
  260.                 }
  261.             }
  262.         }
  263.         return !$return;
  264.     }
  265.     
  266.     /**
  267.      * Construct the {@link $ignore} array
  268.      * @param array strings of files/paths/wildcards to ignore
  269.      * @param 0|1 0 = files to include, 1 = files to ignore
  270.      * @access private
  271.      */
  272.     function _setupIgnore($ignore, $index)
  273.     {
  274.         $ig = array();
  275.         if (is_array($ignore)) {
  276.             for($i=0; $i<count($ignore);$i++) {
  277.                 $ignore[$i] = strtr($ignore[$i], "\\", "/");
  278.                 $ignore[$i] = str_replace('//','/',$ignore[$i]);
  279.  
  280.                 if (!empty($ignore[$i])) {
  281.                     if (!is_numeric(strpos($ignore[$i], '/'))) {
  282.                         $ig[] = $this->_getRegExpableSearchString($ignore[$i]);
  283.                     } else {
  284.                         if (basename($ignore[$i]) . '/' == $ignore[$i]) {
  285.                             $ig[] = $this->_getRegExpableSearchString($ignore[$i]);
  286.                         } else {
  287.                             $ig[] = array($this->_getRegExpableSearchString($ignore[$i]),
  288.                                       $this->_getRegExpableSearchString(basename($ignore[$i])));
  289.                         }
  290.                     }
  291.                 }
  292.             }
  293.             if (count($ig)) {
  294.                 $this->ignore[$index] = $ig;
  295.             } else {
  296.                 $this->ignore[$index] = false;
  297.             }
  298.         } else $this->ignore[$index] = false;
  299.     }
  300.     
  301.     /**
  302.      * Converts $s into a string that can be used with preg_match
  303.      * @param string $s string with wildcards ? and *
  304.      * @return string converts * to .*, ? to ., etc.
  305.      * @access private
  306.      */
  307.     function _getRegExpableSearchString($s)
  308.     {
  309.         $y = '\/';
  310.         if (DIRECTORY_SEPARATOR == '\\') {
  311.             $y = '\\\\';
  312.         }
  313.         $s = str_replace('/', DIRECTORY_SEPARATOR, $s);
  314.         $x = strtr($s, array('?' => '.','*' => '.*','.' => '\\.','\\' => '\\\\','/' => '\\/',
  315.                                 '[' => '\\[',']' => '\\]','-' => '\\-'));
  316.         if (strpos($s, DIRECTORY_SEPARATOR) !== false &&
  317.               strrpos($s, DIRECTORY_SEPARATOR) === strlen($s) - 1) {
  318.             $x = "(?:.*$y$x?.*|$x.*)";
  319.         }
  320.         return $x;
  321.     }
  322.     
  323.     /**
  324.      * Recursively move contents of $struc into associative array
  325.      *
  326.      * The contents of $struc have many indexes like 'dir/subdir/subdir2'.
  327.      * This function converts them to
  328.      * array('dir' => array('subdir' => array('subdir2')))
  329.      * @param array struc is array('dir' => array of files in dir,
  330.      *              'dir/subdir' => array of files in dir/subdir,...)
  331.      * @param array array form of 'dir/subdir/subdir2' array('dir','subdir','subdir2')
  332.      * @return array same as struc but with array('dir' =>
  333.      *              array(file1,file2,'subdir' => array(file1,...)))
  334.      * @access private
  335.      */
  336.     function _setupDirs($struc, $dir, $contents)
  337.     {
  338.         if (!count($dir)) {
  339.             foreach($contents as $dir => $files) {
  340.                 if (is_string($dir)) {
  341.                     if (strpos($dir, '/')) {
  342.                         $test = true;
  343.                         $a = $contents[$dir];
  344.                         unset($contents[$dir]);
  345.                         $b = explode('/', $dir);
  346.                         $c = array_shift($b);
  347.                         if (isset($contents[$c])) {
  348.                             $contents[$c] = $this->_setDir($contents[$c], $this->_setupDirs(array(), $b, $a));
  349.                         } else {
  350.                             $contents[$c] = $this->_setupDirs(array(), $b, $a);
  351.                         }
  352.                     }
  353.                 }
  354.             }
  355.             return $contents;
  356.         }
  357.         $me = array_shift($dir);
  358.         if (!isset($struc[$me])) {
  359.             $struc[$me] = array();
  360.         }
  361.         $struc[$me] = $this->_setupDirs($struc[$me], $dir, $contents);
  362.         return $struc;
  363.     }
  364.  
  365.     
  366.     /**
  367.      * Recursively add all the subdirectories of $contents to $dir without erasing anything in
  368.      * $dir
  369.      * @param array
  370.      * @param array
  371.      * @return array processed $dir
  372.      * @access private
  373.      */
  374.     function _setDir($dir, $contents)
  375.     {
  376.         while(list($one,$two) = each($contents)) {
  377.             if (isset($dir[$one])) {
  378.                 $dir[$one] = $this->_setDir($dir[$one], $contents[$one]);
  379.             } else {
  380.                 $dir[$one] = $two;
  381.             }
  382.         }
  383.         return $dir;
  384.     }
  385.  
  386.     
  387.     /**#@+
  388.      * Sorting functions for the file list
  389.      * @param string
  390.      * @param string
  391.      * @access private
  392.      */
  393.     function sortfiles($a, $b)
  394.     {
  395.         return strnatcasecmp($a['file'],$b['file']);
  396.     }
  397.     
  398.     function mystrucsort($a, $b)
  399.     {
  400.         if (is_numeric($a) && is_string($b)) return 1;
  401.         if (is_numeric($b) && is_string($a)) return -1;
  402.         if (is_numeric($a) && is_numeric($b))
  403.         {
  404.             if ($a > $b) return 1;
  405.             if ($a < $b) return -1;
  406.             if ($a == $b) return 0;
  407.         }
  408.         return strnatcasecmp($a,$b);
  409.     }
  410.     /**#@-*/
  411. }
  412. ?>
  413.