百科狗-知识改变命运!
--

glob() - 寻找与模式匹配的文件路径 - php 文件目录函数

是丫丫呀1年前 (2023-11-21)阅读数 19#技术干货
文章标签文件

glob()

(PHP 4 >= 4.3.0, PHP 5, PHP 7)

寻找与模式匹配的文件路径

说明

glob(string $pattern[,int $flags= 0]): array

glob()函数依照 libc glob()函数使用的规则寻找所有与$pattern匹配的文件路径,类似于一般 shells 所用的规则一样。不进行缩写扩展或参数替代。

参数

$pattern

The pattern. No tilde expansion or parameter substitution is done.

$flags

有效标记有:

  • GLOB_MARK-在每个返回的项目中加一个斜线
  • GLOB_NOSORT-按照文件在目录中出现的原始顺序返回(不排序)
  • GLOB_NOCHECK-如果没有文件匹配则返回用于搜索的模式
  • GLOB_NOESCAPE-反斜线不转义元字符
  • GLOB_BRACE-扩充{a,b,c}来匹配'a','b'或'c'
  • GLOB_ONLYDIR-仅返回与模式匹配的目录项
  • GLOB_ERR-停止并读取错误信息(比如说不可读的目录),默认的情况下忽略所有错误

返回值

返回一个包含有匹配文件/目录的数组。如果出错返回FALSE

Note:

On some systems it is impossible to distinguish between empty match and an error.

更新日志

版本说明
5.1.0GLOB_ERRwas added
4.3.3GLOB_ONLYDIR在 Windows 或者其它不使用 GNU C 库的系统上开始可用。

范例

怎样用glob()方便地替代opendir()和相关函数

以上例程的输出类似于:

funclist.txt size 44686
funcsummary.txt size 267625
quickref.txt size 137820

注释

glob() - 寻找与模式匹配的文件路径 - php 文件目录函数

Note:此函数不能作用于远程文件,被检查的文件必须是可通过服务器的文件系统访问的。

Note:此函数在一些系统上还不能工作(例如一些旧的 Sun OS)。

Note:GLOB_BRACE在一些非 GNU 系统上无效,比如 Solaris。

参见

  • opendir() 打开目录句柄
  • readdir() 从目录句柄中读取条目
  • closedir() 关闭目录句柄
  • fnmatch() 用模式匹配文件名
Since I feel this is rather vague and non-helpful, I thought I'd make a post detailing the mechanics of the glob regex.
glob uses two special symbols that act like sort of a blend between a meta-character and a quantifier. These two characters are the * and ? 
The ? matches 1 of any character except a /
The * matches 0 or more of any character except a /
If it helps, think of the * as the pcre equivalent of .* and ? as the pcre equivalent of the dot (.)
Note: * and ? function independently from the previous character. For instance, if you do glob("a*.php") on the following list of files, all of the files starting with an 'a' will be returned, but * itself would match:
a.php // * matches nothing
aa.php // * matches the second 'a'
ab.php // * matches 'b'
abc.php // * matches 'bc'
b.php // * matches nothing, because the starting 'a' fails
bc.php // * matches nothing, because the starting 'a' fails
bcd.php // * matches nothing, because the starting 'a' fails
It does not match just a.php and aa.php as a 'normal' regex would, because it matches 0 or more of any character, not the character/class/group before it. 
Executing glob("a?.php") on the same list of files will only return aa.php and ab.php because as mentioned, the ? is the equivalent of pcre's dot, and is NOT the same as pcre's ?, which would match 0 or 1 of the previous character.
glob's regex also supports character classes and negative character classes, using the syntax [] and [^]. It will match any one character inside [] or match any one character that is not in [^].
With the same list above, executing 
glob("[ab]*.php) will return (all of them):
a.php // [ab] matches 'a', * matches nothing
aa.php // [ab] matches 'a', * matches 2nd 'a'
ab.php // [ab] matches 'a', * matches 'b'
abc.php // [ab] matches 'a', * matches 'bc'
b.php // [ab] matches 'b', * matches nothing
bc.php // [ab] matches 'b', * matches 'c'
bcd.php // [ab] matches 'b', * matches 'cd'
glob("[ab].php") will return a.php and b.php
glob("[^a]*.php") will return:
b.php // [^a] matches 'b', * matches nothing
bc.php // [^a] matches 'b', * matches 'c'
bcd.php // [^a] matches 'b', * matches 'cd'
glob("[^ab]*.php") will return nothing because the character class will fail to match on the first character. 
You can also use ranges of characters inside the character class by having a starting and ending character with a hyphen in between. For example, [a-z] will match any letter between a and z, [0-9] will match any (one) number, etc.. 
glob also supports limited alternation with {n1, n2, etc..}. You have to specify GLOB_BRACE as the 2nd argument for glob in order for it to work. So for example, if you executed glob("{a,b,c}.php", GLOB_BRACE) on the following list of files:
a.php
b.php
c.php
all 3 of them would return. Note: using alternation with single characters like that is the same thing as just doing glob("[abc].php"). A more interesting example would be glob("te{xt,nse}.php", GLOB_BRACE) on:
tent.php
text.php
test.php
tense.php
text.php and tense.php would be returned from that glob.
glob's regex does not offer any kind of quantification of a specified character or character class or alternation. For instance, if you have the following files:
a.php
aa.php
aaa.php
ab.php
abc.php
b.php
bc.php
with pcre regex you can do ~^a+\.php$~ to return 
a.php
aa.php
aaa.php
This is not possible with glob. If you are trying to do something like this, you can first narrow it down with glob, and then get exact matches with a full flavored regex engine. For example, if you wanted all of the php files in the previous list that only have one or more 'a' in it, you can do this:

glob also does not support lookbehinds, lookaheads, atomic groupings, capturing, or any of the 'higher level' regex functions.
glob does not support 'shortkey' meta-characters like \w or \d.
Those of you with PHP 5 don't have to come up with these wild functions to scan a directory recursively: the SPL can do it.

Not to mention the fact that $file will be an SplFileInfo class, so you can do powerful stuff really easily:

\Luna\luna.msstyles: 4190352 B; modified 2008-04-13
\Luna\Shell\Homestead\shellstyle.dll: 362496 B; modified 2006-02-28
\Luna\Shell\Metallic\shellstyle.dll: 362496 B; modified 2006-02-28
\Luna\Shell\NormalColor\shellstyle.dll: 361472 B; modified 2006-02-28
\Luna.theme: 1222 B; modified 2006-02-28
\Windows Classic.theme: 3025 B; modified 2006-02-28
Total file size: 5281063 bytes
Please note that glob('*') ignores all 'hidden' files by default. This means it does not return files that start with a dot (e.g. ".file").
If you want to match those files too, you can use "{,.}*" as the pattern with the GLOB_BRACE flag.

Note: This also returns the directory special entries . and ..
glob is case sensitive, even on Windows systems.
It does support character classes though, so a case insensitive version of

could be written as 
glob() isn't limited to one directory:

Just be careful when using GLOB_BRACE regarding spaces around the comma:
{includes/*.php,core/*.php} works as expected, but
{includes/*.php, core/*.php} with a leading space, will only match the former as expected but not the latter
unless you have a directory named " core" on your machine with a leading space.
PHP can create such directories quite easily like so:
mkdir(" core");
glob() (array_sum() and array_map() in fact too) can be very useful if you want to calculate the sum of all the files' sizes located in a directory:

Unfortunately there's no way to do this recursively, using glob() (as far as I know).
Note that in case you are using braces with glob you might retrieve duplicated entries for files that matche more than one item :

Result : 
Array
(
  [0] => /path/file_foo.dat
  [1] => /path/file_foobar.dat
  [2] => /path/file_foobar.dat
)
As a follow up to recursively determining all paths (by viajy at yoyo dot org) and opendir being faster than glob (by Sam Yong - hellclanner at live [dot] com).
The list all dirs code didn't seem to work, at least on my server (provided by parazuce [at] gmail [dot] com).
I needed a function to create an unlimited multidimensional array, with the names of the folders/files intact (no realpath's, although that is easily possible). This is so I can simply loop through the array, create an expandable link on the folder name, with all the files inside it.
This is the correct way to recurse I believe (no static, return small arrays to build up the multidimensional array), and includes a check for files/folders beginning with dots.
// may need modifications
function list_files($path)
{
  $files = array();
  
  if(is_dir($path))
  {
    if($handle = opendir($path))
    {
      while(($name = readdir($handle)) !== false)
      {
        if(!preg_match("#^\.#", $name))
        if(is_dir($path . "/" . $name))
        {
          $files[$name] = list_files($path . "/" . $name);
        }
        else
        {
          $files[] = $name;
        }
      }
      
      closedir($handle);
    }
  }
  return $files;
}
print_r(list_files("/path/to/folder"));
// example usage
function list_html($list)
{
  $html = "";
  
  foreach($list as $folder => $file)
  {
    if(is_array($list[$folder]))
    {
      $html .= "> (folder) " . $folder . "
"; $html .= list_html($list[$folder]); } else { $html .= " (file) " . $file . "
"; } } return $html; } echo list_html(list_files("/path/to/folder"));
Don't use glob() if you try to list files in a directory where very much files are stored (>100.000). You get an "Allowed memory size of XYZ bytes exhausted ..." error.
You may try to increase the memory_limit variable in php.ini. Mine has 128MB set and the script will still reach this limit while glob()ing over 500.000 files.
The more stable way is to use readdir() on very large numbers of files: 
You can use multiple asterisks with the glob() - function.
Example:

$paths will contains paths as following examples:
- my/1/dir/xyz.php
- my/bar/dir/bar.php
- my/bar/dir/foo.php
I lost hours looking for the solution for this problem.
glob() wasn't eating up my directory names (stuff like "foobar[]"), and I searched online for some hours, I tried preg_quote to no avail.
I finally found the proper way to escape stuff in glob() in an obscure Python mailing list:

If you want to add a directory path before your pattern, you should do it like this:

preg_quote WILL NOT work in all cases (if any).
First off, it's nice to see all of the different takes on this. Thanks for all of the great examples. 
Fascinated by the foreach usage I was curious how it might work with a for loop. I found that glob was well suited for this, especially compared to opendir. The for loop is always efficient when you want to protect against a potential endless loop. 
$dir=$_SERVER['DOCUMENT_ROOT']."/test/directory_listing/test";
  echo $dir;
  $filesArray=glob($dir."/*.*");  
  
  $line.="
";
  $line.=print_r($filesArray, true);
  $line.="
"; $line.="
"; for($i=0;$i
In some systems (AIX for example) GLOB_BRACE isn't defined and you get the error:
glob() expects parameter 2 to be long, string given in /XX/XX.php

The method may help you in this case. 
A simple function that find all files by extension an return it by an array. 
A function to quickly remove a directory (works in seconds for a hundred thousand files) 
alan at ridersite dot org 18-Mar-2007 03:26 -- Stated '*.*' is the same as '*' -- This is not true as * alone will return directories too and *.* will only return files with an extension such as .pdf or .doc or .php.
Maybe all of you still know this, but it seems that if the directory contains some unresolved symlink, glob() simply ignore those files.
Something I used to sort dir & subdir into array (multidimensional) reflecting dir structure.
  function getRecursiveFolderList($curDir,$currentA=false) 
   {          
    $dirs = glob($curDir . '/*', GLOB_ONLYDIR);   
    
    $cur = 0;
    foreach($dirs as $dir)
     {
      $currentA[$cur]['path'] = $dir;
      $currentA[$cur] = $this->getRecursiveFolderList($dir,$currentA[$cur]);
        
      ++$cur;
     }
    return $currentA;
   }
Here is simple function that will find and remove all files (except "." ones) that match the expression ($match, "*" as wildcard) under starting directory ($path) and all other directories under it.
function rfr($path,$match){
  static $deld = 0, $dsize = 0;
  $dirs = glob($path."*");
  $files = glob($path.$match);
  foreach($files as $file){
   if(is_file($file)){
     $dsize += filesize($file);
     unlink($file);
     $deld++;
   }
  }
  foreach($dirs as $dir){
   if(is_dir($dir)){
     $dir = basename($dir) . "/";
     rfr($path.$dir,$match);
   }
  }
  return "$deld files deleted with a total size of $dsize bytes";
}
Use this to exclude hidden files on MS Windows. 
Recursive glob for PHP>=5.5
function globRecursive($path, $find) {
  $dh = opendir($path);
  while (($file = readdir($dh)) !== false) {
    if (substr($file, 0, 1) == '.') continue;
    $rfile = "{$path}/{$file}";
    if (is_dir($rfile)) {
      foreach (globRecursive($rfile, $find) as $ret) {
        yield $ret;
      }
    } else {
      if (fnmatch($find, $file)) yield $rfile;
    }
  }
  closedir($dh);
}
You can do a recursive file search with yield. 
The example on this page will generate a warning if the glob function does not find any filenames that match the pattern.
The glob function result will only be an array if it finds some files and the foreach statement requires its argument to be an array.
By checking for the possibility that the result of the glob function may not be an array you can eliminate the warning.
Here's a better example: 
For those who need to recursively search a directory tree and cannot or wish not to call a function within itself here is another suggestion.
I tried the previously suggested listdirs_safe() and it didn't seem to find all subfolders in a directory tree.
There are two variations on the same theme.
Single Array.

Multiple arrays.

This will result in the glob looping via "dir/*/*/*/*.." until it is no longer finding a directory structure.
in the example below, i found i got an error if the directory was empty.

I think its because glob()'ing an empty directory returns false, and so calling foreach (false as $value) will obviously break.
to fix this, i did the following:

鹏仔微信 15129739599 鹏仔QQ344225443 鹏仔前端 pjxi.com 共享博客 sharedbk.com

免责声明:我们致力于保护作者版权,注重分享,当前被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理!邮箱:344225443@qq.com)

图片声明:本站部分配图来自网络。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

内容声明:本文中引用的各种信息及资料(包括但不限于文字、数据、图表及超链接等)均来源于该信息及资料的相关主体(包括但不限于公司、媒体、协会等机构)的官方网站或公开发表的信息。部分内容参考包括:(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供参考使用,不准确地方联系删除处理!本站为非盈利性质站点,本着为中国教育事业出一份力,发布内容不收取任何费用也不接任何广告!)