scandir

(PHP 5, PHP 7, PHP 8)

scandir列出指定路径中的文件和目录

说明

scandir(string $directory, int $sorting_order = SCANDIR_SORT_ASCENDING, ?resource $context = null): array|false

返回 array,包含有 directory 中的文件和目录。

参数

directory

要被浏览的目录

sorting_order

默认的排序顺序是按字母升序排列。如果使用了可选参数 sorting_order(设为 1),则排序顺序是按字母降序排列。

context

context 参数的说明见手册中的 Streams API 一章。

返回值

成功则返回包含有文件名的 array,如果失败则返回 false。如果 directory 不是个目录,则返回布尔值 false 并生成一条 E_WARNING 级的错误。

更新日志

版本 说明
8.0.0 现在 context 允许为 null。

示例

示例 #1 简单的 scandir() 示例

<?php
$dir
= '/tmp';
$files1 = scandir($dir);
$files2 = scandir($dir, SCANDIR_SORT_DESCENDING);

print_r($files1);
print_r($files2);
?>

以上示例的输出类似于:

Array
(
    [0] => .
    [1] => ..
    [2] => bar.php
    [3] => foo.txt
    [4] => somedir
)
Array
(
    [0] => somedir
    [1] => foo.txt
    [2] => bar.php
    [3] => ..
    [4] => .
)

注释

小技巧

如已启用fopen 包装器,在此函数中, URL 可作为文件名。关于如何指定文件名详见 fopen()。各种 wapper 的不同功能请参见 支持的协议和封装协议,注意其用法及其可提供的预定义变量。

参见

  • opendir() - 打开目录句柄
  • readdir() - 从目录句柄中读取条目
  • glob() - 寻找与模式匹配的文件路径
  • is_dir() - 判断给定文件名是否是一个目录
  • sort() - 对数组升序排序

添加备注

用户贡献的备注 16 notes

up
855
dwieeb at gmail dot com
12 years ago
Easy way to get rid of the dots that scandir() picks up in Linux environments:

<?php
$directory
= '/path/to/my/directory';
$scanned_directory = array_diff(scandir($directory), array('..', '.'));
?>
up
176
mmda dot nl at gmail dot com
12 years ago
Here is my 2 cents. I wanted to create an array of my directory structure recursively. I wanted to easely access data in a certain directory using foreach. I came up with the following:

<?php
function dirToArray($dir) {

$result = array();

$cdir = scandir($dir);
foreach (
$cdir as $key => $value)
{
if (!
in_array($value,array(".","..")))
{
if (
is_dir($dir . DIRECTORY_SEPARATOR . $value))
{
$result[$value] = dirToArray($dir . DIRECTORY_SEPARATOR . $value);
}
else
{
$result[] = $value;
}
}
}

return
$result;
}
?>

Output
Array
(
[subdir1] => Array
(
[0] => file1.txt
[subsubdir] => Array
(
[0] => file2.txt
[1] => file3.txt
)
)
[subdir2] => Array
(
[0] => file4.txt
}
)
up
29
info at remark dot no
6 years ago
Someone wrote that array_slice could be used to quickly remove directory entries "." and "..". However, "-" is a valid entry that would come before those, so array_slice would remove the wrong entries.
up
24
kodlee at kodleeshare dot net
12 years ago
I needed to find a way to get the full path of all files in the directory and all subdirectories of a directory.
Here's my solution: Recursive functions!

<?php
function find_all_files($dir)
{
$root = scandir($dir);
foreach(
$root as $value)
{
if(
$value === '.' || $value === '..') {continue;}
if(
is_file("$dir/$value")) {$result[]="$dir/$value";continue;}
foreach(
find_all_files("$dir/$value") as $value)
{
$result[]=$value;
}
}
return
$result;
}
?>
up
19
gambit_642 AT hotmailDOTcom
10 years ago
Needed something that could return the contents of single or multiple directories, recursively or non-recursively,
for all files or specified file extensions that would be
accessible easily from any scope or script.

And I wanted to allow overloading cause sometimes I'm too lazy to pass all params.
<?php
class scanDir {
static private
$directories, $files, $ext_filter, $recursive;

// ----------------------------------------------------------------------------------------------
// scan(dirpath::string|array, extensions::string|array, recursive::true|false)
static public function scan(){
// Initialize defaults
self::$recursive = false;
self::$directories = array();
self::$files = array();
self::$ext_filter = false;

// Check we have minimum parameters
if(!$args = func_get_args()){
die(
"Must provide a path string or array of path strings");
}
if(
gettype($args[0]) != "string" && gettype($args[0]) != "array"){
die(
"Must provide a path string or array of path strings");
}

// Check if recursive scan | default action: no sub-directories
if(isset($args[2]) && $args[2] == true){self::$recursive = true;}

// Was a filter on file extensions included? | default action: return all file types
if(isset($args[1])){
if(
gettype($args[1]) == "array"){self::$ext_filter = array_map('strtolower', $args[1]);}
else
if(
gettype($args[1]) == "string"){self::$ext_filter[] = strtolower($args[1]);}
}

// Grab path(s)
self::verifyPaths($args[0]);
return
self::$files;
}

static private function
verifyPaths($paths){
$path_errors = array();
if(
gettype($paths) == "string"){$paths = array($paths);}

foreach(
$paths as $path){
if(
is_dir($path)){
self::$directories[] = $path;
$dirContents = self::find_contents($path);
} else {
$path_errors[] = $path;
}
}

if(
$path_errors){echo "The following directories do not exists<br />";die(var_dump($path_errors));}
}

// This is how we scan directories
static private function find_contents($dir){
$result = array();
$root = scandir($dir);
foreach(
$root as $value){
if(
$value === '.' || $value === '..') {continue;}
if(
is_file($dir.DIRECTORY_SEPARATOR.$value)){
if(!
self::$ext_filter || in_array(strtolower(pathinfo($dir.DIRECTORY_SEPARATOR.$value, PATHINFO_EXTENSION)), self::$ext_filter)){
self::$files[] = $result[] = $dir.DIRECTORY_SEPARATOR.$value;
}
continue;
}
if(
self::$recursive){
foreach(
self::find_contents($dir.DIRECTORY_SEPARATOR.$value) as $value) {
self::$files[] = $result[] = $value;
}
}
}
// Return required for recursive search
return $result;
}
}
?>

Usage:
scanDir::scan(path(s):string|array, [file_extensions:string|array], [subfolders?:true|false]);
<?php
//Scan a single directory for all files, no sub-directories
$files = scanDir::scan('D:\Websites\temp');

//Scan multiple directories for all files, no sub-dirs
$dirs = array(
'D:\folder';
'D:\folder2';
'C:\Other';
);
$files = scanDir::scan($dirs);

// Scan multiple directories for files with provided file extension,
// no sub-dirs
$files = scanDir::scan($dirs, "jpg");
//or with an array of extensions
$file_ext = array(
"jpg",
"bmp",
"png"
);
$files = scanDir::scan($dirs, $file_ext);

// Scan multiple directories for files with any extension,
// include files in recursive sub-folders
$files = scanDir::scan($dirs, false, true);

// Multiple dirs, with specified extensions, include sub-dir files
$files = scanDir::scan($dirs, $file_ext, true);
?>
up
48
eep2004 at ukr dot net
10 years ago
Fastest way to get a list of files without dots.
<?php
$files
= array_slice(scandir('/path/to/directory/'), 2);
up
5
artmanniako at gmail dot com
5 years ago
How i solved problem with '.' and '..'

$x = scandir__DIR__; //any directory
foreach ($x as $key => $value) {
if ('.' !== $value && '..' !== $value){
echo $value;
}
}
Simple and working
up
5
coolbikram0 at gmail dot com
2 years ago
A simple recursive function to list all files and subdirectories in a directory:
<?php
function listAllFiles($dir) {
$array = array_diff(scandir($dir), array('.', '..'));

foreach (
$array as &$item) {
$item = $dir . $item;
}
unset(
$item);
foreach (
$array as $item) {
if (
is_dir($item)) {
$array = array_merge($array, listAllFiles($item . DIRECTORY_SEPARATOR));
}
}
return
$array;
}
?>
up
2
csaba at alum dot mit dot edu
19 years ago
Scandir on steroids:
For when you want to filter your file list, or only want to list so many levels of subdirectories...

<?php
function dirList($path="", $types=2, $levels=1, $aFilter=array()) {
// returns an array of the specified files/directories
// start search in $path (defaults to current working directory)
// return $types: 2 => files; 1 => directories; 3 => both;
// $levels: 1 => look in the $path only; 2 => $path and all children;
// 3 => $path, children, grandchildren; 0 => $path and all subdirectories;
// less than 0 => complement of -$levels, OR everything starting -$levels down
// e.g. -1 => everthing except $path; -2 => all descendants except $path + children
// Remaining argument(s) is(are) a filter array(list) of regular expressions which operate on the full path.
// First character (before the '/' of the regExp) '-' => NOT.
// First character (after a possible '-') 'd' => apply to directory name
// The filters may be passed in as an array of strings or as a list of strings
// Note that output directories are prefixed with a '*' (done in the line above the return)
$dS = DIRECTORY_SEPARATOR;
if (!(
$path = realpath($path?$path:getcwd()))) return array(); // bad path
// next line rids terminating \ on drives (works since c: == c:\ on PHP). OK in *nix?
if (substr($path,-1)==$dS) $path = substr($path,0,-1);
if (
is_null($types)) $types = 2;
if (
is_null($levels)) $levels = 1;
if (
is_null($aFilter)) $aFilter=array();

// last argument may be passed as a list or as an array
$aFilter = array_slice(func_get_args(),3);
if (
$aFilter && gettype($aFilter[0])=="array") $aFilter=$aFilter[0];
$adFilter = array();
// now move directory filters to separate array:
foreach ($aFilter as $i=>$filter) // for each directory filter...
if (($pos=stripos(" $filter","d")) && $pos<3) { // next line eliminates the 'd'
$adFilter[] = substr($filter,0,$pos-1) . substr($filter,$pos);
unset(
$aFilter[$i]); }
$aFilter = array_merge($aFilter); // reset indeces

$aRes = array(); // results, $aAcc is an Accumulator
$aDir = array($path); // dirs to check
for ($i=$levels>0?$levels++:-1;($aAcc=array())||$i--&&$aDir;$aDir=$aAcc)
while (
$dir = array_shift($aDir))
foreach (
scandir ($dir) as $fileOrDir)
if (
$fileOrDir!="." && $fileOrDir!="..") {
if (
$dirP = is_dir ($rp="$dir$dS$fileOrDir"))
if (
pathFilter("$rp$dS", $adFilter))
$aAcc[] = $rp;
if (
$i<$levels-1 && ($types & (2-$dirP)))
if (
pathFilter($rp, $aFilter))
$aRes[] = ($dirP?"*":"") . $rp; }
return
$aRes;
}
?>

example usage:
<?php
define
("_", NULL);
// this will find all non .jpg, non .Thumbs.db files under c:\Photo
$aFiles = dirList('c:\Photo', _, 0, '-/\.jpg$/i', '-/\\\\Thumbs.db$/');
$aFiles = dirList(); // find the files in the current directory
// next lines will find .jpg files in non Photo(s) subdirectories, excluding Temporary Internet Files
set_time_limit(60); // iterating from the top level can take a while
$aFiles = dirList("c:\\", _, 0, '/\.jpg$/i', '-d/\\\\Photos?$/i', '-d/Temporary Internet/i');
?>

Note that this function will consume a lot of time if scanning large
directory structures (which is the reason for the '[-]d/.../' filters).

Csaba Gabor from Vienna
up
3
Pawel Dlugosz
19 years ago
For directory containing files like (for example) -.jpg the results of scandir are a little "weird" ;)

<?php

$dir
= '/somedir';
$files = scandir($dir);
print_r($files);
?>

Array
(
[0] => -.jpg
[1] => .
[2] => ..
[3] => foo.txt
[4] => somedir
)

Beware - sorting is in ASCII order :)
up
3
Stan P. van de Burgt
20 years ago
scandir() with regexp matching on file name and sorting options based on stat().

<?php
function myscandir($dir, $exp, $how='name', $desc=0)
{
$r = array();
$dh = @opendir($dir);
if (
$dh) {
while ((
$fname = readdir($dh)) !== false) {
if (
preg_match($exp, $fname)) {
$stat = stat("$dir/$fname");
$r[$fname] = ($how == 'name')? $fname: $stat[$how];
}
}
closedir($dh);
if (
$desc) {
arsort($r);
}
else {
asort($r);
}
}
return(
array_keys($r));
}

$r = myscandir('./book/', '/^article[0-9]{4}\.txt$/i', 'ctime', 1);
print_r($r);
?>

files can be sorted on name and stat() attributes, ascending and descending:

name file name
dev device number
ino inode number
mode inode protection mode
nlink number of links
uid userid of owner
gid groupid of owner
rdev device type, if inode device *
size size in bytes
atime time of last access (Unix timestamp)
mtime time of last modification (Unix timestamp)
ctime time of last inode change (Unix timestamp)
blksize blocksize of filesystem IO *
blocks number of blocks allocated
up
1
simon dot riget at gmail dot com
8 years ago
This is a simple and versatile function that returns an array tree of files, matching wildcards:

<?php
// List files in tree, matching wildcards * and ?
function tree($path){
static
$match;

// Find the real directory part of the path, and set the match parameter
$last=strrpos($path,"/");
if(!
is_dir($path)){
$match=substr($path,$last);
while(!
is_dir($path=substr($path,0,$last)) && $last!==false)
$last=strrpos($path,"/",-1);
}
if(empty(
$match)) $match="/*";
if(!
$path=realpath($path)) return;

// List files
foreach(glob($path.$match) as $file){
$list[]=substr($file,strrpos($file,"/")+1);
}

// Process sub directories
foreach(glob("$path/*", GLOB_ONLYDIR) as $dir){
$list[substr($dir,strrpos($dir,"/",-1)+1)]=tree($dir);
}

return @
$list;
}
?>
up
1
fazle dot elahee at gmail dot com
12 years ago
/**
* This function will scan all files recursively in the sub-folder and folder.
*
* @author Fazle Elahee
*
*/

function scanFileNameRecursivly($path = '', &$name = array() )
{
$path = $path == ''? dirname(__FILE__) : $path;
$lists = @scandir($path);

if(!empty($lists))
{
foreach($lists as $f)
{

if(is_dir($path.DIRECTORY_SEPARATOR.$f) && $f != ".." && $f != ".")
{
scanFileNameRecursivly($path.DIRECTORY_SEPARATOR.$f, &$name);
}
else
{
$name[] = $path.DIRECTORY_SEPARATOR.$f;
}
}
}
return $name;
}

$path = "/var/www/SimplejQueryDropdowns";
$file_names = scanFileNameRecursivly($path);

echo "<pre>";
var_dump($file_names);
echo "</pre>";
up
1
fatpratmatt dot at dot gmail dot com
16 years ago
This function generates a list of all files in the chosen directory and all subdirectories, throws them into a NON-multidimentional array and returns them.

Most of the recursive functions on this page only return a multi-dimensional array.

This is actually a modification of some one else's function (thanks mail at bartrail dot de ;])

<?php
function scanDirectories($rootDir, $allData=array()) {
// set filenames invisible if you want
$invisibleFileNames = array(".", "..", ".htaccess", ".htpasswd");
// run through content of root directory
$dirContent = scandir($rootDir);
foreach(
$dirContent as $key => $content) {
// filter all files not accessible
$path = $rootDir.'/'.$content;
if(!
in_array($content, $invisibleFileNames)) {
// if content is file & readable, add to array
if(is_file($path) && is_readable($path)) {
// save file name with path
$allData[] = $path;
// if content is a directory and readable, add path and name
}elseif(is_dir($path) && is_readable($path)) {
// recursive callback to open new directory
$allData = scanDirectories($path, $allData);
}
}
}
return
$allData;
}
?>

Example output:

print_r(scanDirectories("www"));
---
Array
(
[0] => www/index.php
[1] => www/admin.php
[3] => www/css/css.css
[4] => www/articles/2007/article1.txt
[4] => www/articles/2006/article1.txt
[8] => www/img/img1.png
)
up
0
SPekary
7 years ago
Unless you specify no sorting, file names are sorted in ASCII alphabetic order, meaning numbers first, then uppercase, then lowercase letters, even on operating systems whose file system ignores the case of file names when it does its own sorting.

For example, on Mac OS, the following files will appear in this order in the Finder, when your disk is formated using the standard file system:
1file.php
a.inc
B.txt
c.txt

However, scandir will produce an array in the following order:
1file.php
B.txt
a.inc
c.txt
up
1
carneiro at isharelife dot com dot br
12 years ago
<?php
/**
* Get an array that represents directory tree
* @param string $directory Directory path
* @param bool $recursive Include sub directories
* @param bool $listDirs Include directories on listing
* @param bool $listFiles Include files on listing
* @param regex $exclude Exclude paths that matches this regex
*/
function directoryToArray($directory, $recursive = true, $listDirs = false, $listFiles = true, $exclude = '') {
$arrayItems = array();
$skipByExclude = false;
$handle = opendir($directory);
if (
$handle) {
while (
false !== ($file = readdir($handle))) {
preg_match("/(^(([\.]){1,2})$|(\.(svn|git|md))|(Thumbs\.db|\.DS_STORE))$/iu", $file, $skip);
if(
$exclude){
preg_match($exclude, $file, $skipByExclude);
}
if (!
$skip && !$skipByExclude) {
if (
is_dir($directory. DIRECTORY_SEPARATOR . $file)) {
if(
$recursive) {
$arrayItems = array_merge($arrayItems, directoryToArray($directory. DIRECTORY_SEPARATOR . $file, $recursive, $listDirs, $listFiles, $exclude));
}
if(
$listDirs){
$file = $directory . DIRECTORY_SEPARATOR . $file;
$arrayItems[] = $file;
}
} else {
if(
$listFiles){
$file = $directory . DIRECTORY_SEPARATOR . $file;
$arrayItems[] = $file;
}
}
}
}
closedir($handle);
}
return
$arrayItems;
}
?>
To Top