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

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