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

Source for file glob.php

Documentation is available at glob.php

  1. <?php
  2. // $Id: glob.php,v 1.7 2007/04/17 10:09:56 arpad Exp $
  3.  
  4.  
  5. if (!defined('GLOB_ERR')) {
  6.     define('GLOB_ERR', 1);
  7. }
  8. if (!defined('GLOB_MARK')) {
  9.     define('GLOB_MARK', 2);
  10. }
  11. if (!defined('GLOB_NOSORT')) {
  12.     define('GLOB_NOSORT', 4);
  13. }
  14. if (!defined('GLOB_NOCHECK')) {
  15.     define('GLOB_NOCHECK', 16);
  16. }
  17. if (!defined('GLOB_NOESCAPE')) {
  18.     define('GLOB_NOESCAPE', 64);
  19. }
  20. if (!defined('GLOB_BRACE')) {
  21.     define('GLOB_BRACE', 1024);
  22. }
  23. if (!defined('GLOB_ONLYDIR')) {
  24.     define('GLOB_ONLYDIR', 8192);
  25. }
  26.  
  27. /**
  28.  * Replace glob()
  29.  *
  30.  * @category    PHP
  31.  * @package     PHP_Compat
  32.  * @license     LGPL - http://www.gnu.org/licenses/lgpl.html
  33.  * @copyright   2004-2007 Aidan Lister <aidan@php.net>, Arpad Ray <arpad@php.net>
  34.  * @link        http://php.net/glob
  35.  * @author      Arpad Ray <arpad@php.net>
  36.  * @version     $Revision: 1.7 $
  37.  * @since       PHP 4.3.0
  38.  * @require     PHP 3.0.9 (preg_replace)
  39.  */
  40. function php_compat_glob($pattern, $flags = 0)
  41. {
  42.     $return_failure = ($flags & GLOB_NOCHECK) ? array($pattern) : false;
  43.     
  44.     // build path to scan files
  45.     $path = '.';
  46.     $wildcards_open = '*?[';
  47.     $wildcards_close = ']';
  48.     if ($flags & GLOB_BRACE) {
  49.         $wildcards_open .= '{';
  50.         $wildcards_close .= '}';
  51.     }
  52.     $prefix_length = strcspn($pattern, $wildcards_open);
  53.     if ($prefix_length) {
  54.         if (DIRECTORY_SEPARATOR == '\\')  {
  55.             $sep = ($flags & GLOB_NOESCAPE) ? '[\\\\/]' : '(?:/|\\\\(?![' . $wildcards_open . $wildcards_close . ']))';
  56.         } else {
  57.             $sep = '/';
  58.         }
  59.         if (preg_match('#^(.*)' . $sep . '#', substr($pattern, 0, $prefix_length), $matches)) {
  60.             $path = $matches[1];
  61.         }
  62.     }
  63.     $recurse = (strpos($pattern, DIRECTORY_SEPARATOR, $prefix_length) !== false);
  64.     
  65.     // scan files
  66.     $files = php_compat_glob_scan_helper($path, $flags, $recurse);
  67.     if ($files === false) {
  68.         return $return_failure;
  69.     }
  70.  
  71.     // build preg pattern
  72.     $pattern = php_compat_glob_convert_helper($pattern, $flags);
  73.     $convert_patterns = array('/\{([^{}]*)\}/e', '/\[([^\]]*)\]/e');
  74.     $convert_replacements = array(
  75.         'php_compat_glob_brace_helper(\'$1\', $flags)',
  76.         'php_compat_glob_charclass_helper(\'$1\', $flags)'
  77.     );
  78.     while ($flags & GLOB_BRACE) {
  79.         $new_pattern = preg_replace($convert_patterns, $convert_replacements, $pattern);
  80.         if ($new_pattern == $pattern) {
  81.             break;
  82.         }
  83.         $pattern = $new_pattern;
  84.     }
  85.     $pattern = '#^' . $pattern . '\z#';
  86.  
  87.     // process files
  88.     $results = array();
  89.     foreach ($files as $file => $dir) {
  90.         if (!preg_match($pattern, $file, $matches)) {
  91.             continue;
  92.         }
  93.         if (($flags & GLOB_ONLYDIR) && !$dir) {
  94.             continue;
  95.         }
  96.         $file = (($flags & GLOB_MARK) && $dir) ? $file . DIRECTORY_SEPARATOR : $file;
  97.         if ($flags & GLOB_BRACE) {
  98.             // find last matching subpattern
  99.             $rank = 0;
  100.             for ($i = 1, $matchc = count($matches); $i < $matchc; $i++) {
  101.                 if (strlen($matches[$i])) {
  102.                     $rank = $i;
  103.                 }
  104.             }
  105.             $file = array($file, $rank);
  106.         }
  107.         $results[] = $file;
  108.     }
  109.     
  110.     if ($flags & GLOB_BRACE) {
  111.         usort($results, ($flags & GLOB_NOSORT) ? 'php_compat_glob_brace_nosort_helper' : 'php_compat_glob_brace_sort_helper');
  112.     } else if ($flags & GLOB_NOSORT) {
  113.         usort($results, 'php_compat_glob_nosort_helper');
  114.     } else {
  115.         sort($results);
  116.     }
  117.     
  118.     // array_values() for php 4 +
  119.     $reindex = array();
  120.     foreach ($results as $result) {
  121.         $reindex[] = ($flags & GLOB_BRACE) ? $result[0] : $result;
  122.     }
  123.  
  124.     if (($flags & GLOB_NOCHECK) && !count($reindex)) {
  125.         return $return_failure;
  126.     }
  127.     return $reindex;
  128. }
  129.  
  130. /**
  131.  * Scans a path
  132.  *
  133.  * @param string $path 
  134.  *   the path to scan
  135.  * @param int $flags 
  136.  *   the flags passed to glob()
  137.  * @param bool $recurse 
  138.  *   true to scan recursively
  139.  * @return mixed 
  140.  *   an array of files in the given path where the key is the path,
  141.  *   and the value is 1 if the file is a directory, 0 if it isn't.
  142.  *   Returns false on unrecoverable errors, or all errors when
  143.  *   GLOB_ERR is on.
  144.  */
  145. function php_compat_glob_scan_helper($path, $flags, $recurse = false)
  146. {
  147.     if (!is_readable($path)) {
  148.         return false;
  149.     }
  150.     $results = array();
  151.     if (is_dir($path)) {
  152.         $fp = opendir($path);
  153.         if (!$fp) {
  154.             return ($flags & GLOB_ERR) ? false : array($path);
  155.         }
  156.         if ($path != '.') {
  157.             $results[$path] = 1;
  158.         }
  159.         while (($file = readdir($fp)) !== false) {
  160.             if ($file[0] == '.' || $file == '..') {
  161.                 continue;
  162.             }
  163.             $filepath = ($path == '.') ? $file : $path . DIRECTORY_SEPARATOR . $file;
  164.             if (is_dir($filepath)) {
  165.                 $results[$filepath] = 1;
  166.                 if (!$recurse) {
  167.                     continue;
  168.                 }
  169.                 $files = php_compat_glob_scan_helper($filepath, $flags);
  170.                 if ($files === false) {
  171.                     if ($flags & GLOB_ERR) {
  172.                         return false;
  173.                     }
  174.                     continue;
  175.                 }
  176.                 // array_merge for php 4 +
  177.                 foreach ($files as $rfile => $rdir) {
  178.                     $results[$rfile] = $rdir;
  179.                 }
  180.                 continue;
  181.             }
  182.             $results[$filepath] = 0;
  183.         }
  184.         closedir($fp);
  185.     } else {
  186.         $results[$path] = 0;
  187.     }
  188.     return $results;
  189. }
  190.  
  191. /**
  192.  * Converts a section of a glob pattern to a PCRE pattern
  193.  *
  194.  * @param string $input 
  195.  *   the pattern to convert
  196.  * @param int $flags 
  197.  *   the flags passed to glob()
  198.  * @return string 
  199.  *   the escaped input
  200.  */
  201. function php_compat_glob_convert_helper($input, $flags)
  202. {
  203.     $opens = array(
  204.         '{' => array('}', 0),
  205.         '[' => array(']', 0),
  206.         '(' => array(')', 0)
  207.     );
  208.     $ret = '';
  209.     for ($i = 0, $len = strlen($input); $i < $len; $i++) {
  210.         $skip = false;
  211.         $c = $input[$i];
  212.         $escaped = ($i && $input[$i - 1] == '\\' && ($flags & GLOB_NOCHECK == false));
  213.         
  214.         // skips characters classes and subpatterns, they are escaped in their respective helpers
  215.         foreach ($opens as $k => $v) {
  216.             if ($v[1]) {
  217.                 if ($c == $v[0] && !$escaped) {
  218.                     --$opens[$k][1];
  219.                     $ret .= $c;
  220.                     continue 2;
  221.                 }
  222.                 $skip = true;
  223.             }
  224.         }
  225.         if (isset($opens[$c])) {
  226.             if (!$escaped) {
  227.                 ++$opens[$c][1];
  228.             }
  229.             $ret .= $c;
  230.             continue;
  231.         }
  232.         if ($skip) {
  233.             $ret .= $c;
  234.             continue;
  235.         }
  236.         
  237.         // converts wildcards
  238.         switch ($c) {
  239.         case '*':
  240.             $ret .= $escaped ? '*' : '.*';
  241.             continue 2;
  242.         case '?':
  243.             if ($escaped) {
  244.                 continue;
  245.             }
  246.             $ret .= '.';
  247.             continue 2;
  248.         }
  249.         $ret .= preg_quote($c, '#');
  250.     }
  251.     return $ret;
  252. }
  253.  
  254. /**
  255.  * Converts glob braces
  256.  *
  257.  * @param string $brace 
  258.  *   the contents of the braces to convert
  259.  * @param int $flags 
  260.  *   the flags passed to glob()
  261.  * @return string 
  262.  *   a PCRE subpattern of alternatives
  263.  */
  264. function php_compat_glob_brace_helper($brace, $flags)
  265. {
  266.     $alternatives = explode(',', $brace);
  267.     for ($i = count($alternatives); $i--;) {
  268.         $alternatives[$i] = php_compat_glob_convert_helper($alternatives[$i], $flags);
  269.     }
  270.     return '(?:(' . implode(')|(', $alternatives) . '))';
  271. }
  272.  
  273. /**
  274.  * Converts glob character classes
  275.  *
  276.  * @param string $class 
  277.  *   the contents of the class to convert
  278.  * @param int $flags 
  279.  *   the flags passed to glob()
  280.  * @return string 
  281.  *   a PCRE character class
  282.  */
  283. function php_compat_glob_charclass_helper($class, $flags)
  284. {
  285.     if (strpos($class, '-') !== false) {
  286.         $class = strtr($class, array('-' => '')) . '-';
  287.     }
  288.     if (strpos($class, ']') !== false) {
  289.         $class = ']' . strtr($class, array(']' => ''));
  290.     }
  291.     if (strpos($class, '^') !== false) {
  292.         $class = '\^' . strtr($class, array('^' => ''));
  293.     }
  294.     return '[' . strtr($class, array('#' => '\#')) . ']';
  295. }
  296.  
  297. /**
  298.  * Callback sort function for GLOB_NOSORT
  299.  *
  300.  * Sorts first by the base name, then in reverse by the extension
  301.  */
  302. {
  303.     $operands = array(array('full' => $a), array('full' => $b));
  304.     foreach ($operands as $k => $v) {
  305.         $v['pos'] = strrpos($v['full'], '.');
  306.         if ($v['pos'] === false) {
  307.             $v['pos'] = strlen($v['full']) - 1;
  308.         }
  309.         $v['slash'] = strrpos($v['full'], DIRECTORY_SEPARATOR);
  310.         if ($v['slash'] === false) {
  311.             $v['slash'] = strlen($v['full']) - 1;
  312.         }
  313.         $operands[$k]['dir'] = substr($v['full'], 0, $v['slash']);
  314.         $operands[$k]['base'] = substr($v['full'], $v['slash'], $v['pos'] - $v['slash']);
  315.         $operands[$k]['ext'] = substr($v['full'], $v['pos'] + 1);
  316.     }
  317.     $dir_cmp = strcmp($operands[0]['dir'], $operands[1]['dir']);
  318.     if ($dir_cmp == 0) {
  319.         $base_cmp = strcmp($operands[0]['base'], $operands[1]['base']);
  320.         if ($base_cmp == 0) {
  321.             $ext_cmp = strcmp($operands[0]['ext'], $operands[1]['ext']);
  322.             return -$ext_cmp;
  323.         }
  324.         return $base_cmp;
  325.     }
  326.     return -$dir_cmp;
  327. }
  328.  
  329. /**
  330.  * Callback sort function for GLOB_BRACE
  331.  *
  332.  * Each argument should be an array where the first element is the
  333.  * file path, and the second is its rank. The rank is the number of
  334.  * alternatives between this match and the beginning of the brace.
  335.  */
  336. {
  337.     if ($a[1] == $b[1]) {
  338.         return strcmp($a[0], $b[0]);
  339.     }
  340.     return ($a[1] < $b[1]) ? -1 : 1;
  341. }
  342.  
  343. /**
  344.  * Callback sort function for (GLOB_BRACE | GLOB_NOSORT)
  345.  *
  346.  * Receives the same arguments php_compat_glob_brace_sort_helper()
  347.  */
  348. {
  349.     if ($a[1] == $b[1]) {
  350.         $len_a = strlen($a[0]);
  351.         $len_b = strlen($b[0]);
  352.         if ($len_a == $len_b) { 
  353.             return -strcmp($a[0], $b[0]);
  354.         }
  355.         return ($len_a < $len_b) ? -1 : 1;
  356.     }
  357.     return ($a[1] < $b[1]) ? -1 : 1;
  358. }
  359.  
  360. if (!function_exists('glob')) {
  361.     function glob($pattern, $flags = 0)
  362.     {
  363.         return php_compat_glob($pattern, $flags);
  364.     }
  365. }
  366.  
  367. ?>

Documentation generated on Mon, 11 Mar 2019 15:01:54 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.