PHP Conference Japan 2024

opendir

(PHP 4, PHP 5, PHP 7, PHP 8)

opendir開啟目錄控制代碼

描述

opendir(string $directory, ?resource $context = null): resource|false

開啟一個目錄控制代碼,以供後續的 closedir()readdir()rewinddir() 呼叫中使用。

參數

directory

要開啟的目錄路徑。

context

關於 context 參數的描述,請參閱手冊的串流章節

傳回值

成功時傳回一個目錄控制代碼 resource,失敗時傳回 false

錯誤/例外

失敗時,會發出一個 E_WARNING

這可能發生在 directory 不是有效的目錄、由於權限限制而無法開啟目錄或由於檔案系統錯誤而導致。

變更日誌

版本 描述
8.0.0 context 現在可為 null。

範例

範例 #1 opendir() 範例

<?php
$dir
= "/etc/php5/";

// 開啟一個已知的目錄,並繼續讀取其內容
if (is_dir($dir)) {
if (
$dh = opendir($dir)) {
while ((
$file = readdir($dh)) !== false) {
echo
"檔案名稱: $file : 檔案類型: " . filetype($dir . $file) . "\n";
}
closedir($dh);
}
}
?>

上述範例會輸出類似以下內容:

filename: . : filetype: dir
filename: .. : filetype: dir
filename: apache : filetype: dir
filename: cgi : filetype: dir
filename: cli : filetype: dir

參見

  • is_dir() - 判斷檔案名稱是否為目錄
  • readdir() - 從目錄控制代碼讀取條目
  • dir() - 傳回 Directory 類別的實例

新增註解

使用者提供的註解 33 條註解

8
sergio dot barrios at upr dot edu dot cu
8 年前
在目錄中搜尋資料夾或檔案的迭代函式。

<?php

$root
= '../Classes';
$search_parameter = "CachedObjectStorageFactory.php";

//如果我們將函式 spider 呼叫為 spider($root);
//會顯示所有目錄內容,包括子目錄

//如果我們將函式 spider 呼叫為 spider('../Classes', 'Shared');
//則會顯示目錄的地址

spider($root, $search_parameter);
closedir();

function
spider($dir,$fileName=""){

$handle = opendir($dir);

while(
$file= readdir($handle)){

if(
$file != "." && $file != ".."){

if(
$fileName=="")
echo
$dir."/".$file."<br>";
else
if(
$file == $fileName)
echo
$dir."/".$file."<br>";


if(!
is_file($dir."/".$file))
spider($dir."/".$file,$fileName);

}
}

}

?>
9
hz_php at hotmail dot com { hussam alzahabi }
8 年前
有時程式設計師需要存取具有阿拉伯名稱的資料夾內容,但 opendir 函式會傳回 null 資源 ID。

為此,我們必須使用 iconv 函式將 dirname 字元集從 utf-8 轉換為 windows-1256,前提是 preg_match 函式檢測到阿拉伯字元並額外使用 " U " 來啟用多位元組匹配。

<?php

$dir
= ("./"); // 指向此檔案的目錄

// 偵測路徑是否包含阿拉伯文字元,並使用 "u" 選項啟用多位元組字元比對功能

if (preg_match('#[\x{0600}-\x{06FF}]#iu', $dir) )
{

// 將輸入 (utf-8) 轉換為輸出 (windows-1256)

$dir = iconv("utf-8","windows-1256",$dir);

}

if(
is_dir($dir) )
{


if( (
$dh = opendir($dir) ) !== null )
{


while ( (
$file = readdir($dh) ) !== false )
{


echo
"檔案名稱: ".$file ." 檔案類型 : ".filetype($dir.$file)."<br/>";


}

}


}

?>
8
DaveRandom
15 年前
關於 Matt 關於 Windows 網路磁碟機的文章的一些注意事項

由於 system() 指令會將執行的 shell 指令的輸出直接寫入輸出緩衝區,如果您希望隱藏對應指令的傳回值(例如「命令已成功完成」或錯誤訊息)不讓網頁瀏覽器顯示,您需要修改傳送到 shell 的指令,以便隱藏該指令的輸出。

您可能會想「為什麼不直接使用 exec()?」這是一個合理的問題,但由於某些原因,它並不總是有效 - 我猜這是另一個 NT 使用者權限問題。如果您想確保您的應用程式能夠運作,而不會在主機系統上發生任何問題,請使用 system() 指令。

在 Windows 命令 shell 中,您可以透過使用管道將輸出 (1) 和錯誤 (2) 訊息都傳送到「nul」來隱藏指令的輸出,換句話說,在指令結尾加上「>nul 2>&1」。在 Matt 的文章中,「net use...」指令中的使用者名稱和密碼順序需要切換。

這裡 (http://networkm.co.uk/static/drive.html) 是一個我撰寫的函式,可以根據目前已對應且 PHP 可存取的磁碟機代號,動態選擇要使用的磁碟機代號。

<?php

// 定義 shell 指令的參數
$location = "\\\\伺服器名稱\\分享名稱";
$user = "使用者名稱";
$pass = "密碼";
$letter = "Z";

// 對應磁碟機
system("net use ".$letter.": \"".$location."\" ".$pass." /user:".$user." /persistent:no>nul 2>&1");

// 開啟目錄
$dir = opendir($letter.":/一個/範例/路徑")

...

?>
2
sandy at montana-riverboats dot com
20 年前
<?php
/*
** 這個遞迴檔案列表器一次只讀取一個頁面,
** 因此在操作大型系統時不會花費太多時間載入......每個頁面都有一個「上一層」連結。
*/

$PHP_SELF = $_SERVER['PHP_SELF'];
$DOCUMENT_ROOT = $_SERVER['DOCUMENT_ROOT'];
# 啟用下一行(並停用上一行)以在
# $DOCUMENT_ROOT/~anybody 環境中使用此腳本。
#$DOCUMENT_ROOT="/home/sandy/public_html/";

$tdir = $_GET['dir'];
echo
"tdir==$tdir<br>";
$tparent_path = $_GET['parent_path'];
$dbg = $_GET['dbg'];

if(!
strstr($tdir, $DOCUMENT_ROOT))
$tdir = getcwd();
if(!
strstr($tparent_path, $DOCUMENT_ROOT))
$tparent_path = $tdir;

if (!isset (
$tdir))
{
$dir = getcwd ();
}
else
$dir = $tdir;

if (!isset (
$tparent_path))
{
$parent_path = $dir;
}
else
$parent_path = $tparent_path;

echo
"<br>";
if (!isset (
$tdir))
{
$upurl = $PHP_SELF;
}
else
{
if (
$parent_path == $DOCUMENT_ROOT)
$parent_parent_path = $parent_path;
else
$parent_parent_path = dirname ($parent_path);
$upurl = $PHP_SELF."?dir=".$parent_path."&parent_path=".
$parent_parent_path;
}

if(
$dbg==1)
{
echo
"PHP_SELF: $PHP_SELF<br>\n";
echo
"DOCUMENT_ROOT: $DOCUMENT_ROOT<br>\n";
echo
"dir: $dir<br>\n";
echo
"parent_path: $parent_path<br>\n";
echo
"upurl: $upurl<br>\n";
}

echo
"<a href=\"$upurl\"> <h3>上一層</h3> </a>\n";
echo
"<h2>$dir</h2>\n";

create_tree ($dir, $parent_path);

function
urlFromPath ($path)
{
global
$PHP_SELF;
global
$DOCUMENT_ROOT;
$prefix = "";
if (
substr ($path, 0, 1) != "/")
$prefix = "/";
$url = $prefix.ereg_replace ($DOCUMENT_ROOT, "", $path);
return
$url;
}

function
create_tree ($dir, $parent_path)
{
if (
$handle = opendir ($dir))
{
$i = 0;
while (
false !== ($file = @readdir ($handle)))
{
if (
$file != "." && $file != "..")
{
$list[$i] = $file;
$i++;
}
}
$dir_length = count ($list);
echo
"<ul>";
for (
$i = 0; $i < $dir_length; $i++)
{
global
$PHP_SELF;
global
$DOCUMENT_ROOT;
$label = $list[$i];
$test = $dir."/".$label;
$alink = $dir."/".ereg_replace(" ","%20",$label);
if (!
strstr ($PHP_SELF, $label))
{
if (
is_dir ($test))
{
$tmp = $PHP_SELF. "?dir=".$alink."&parent_path=".$dir;
$url = ereg_replace(" ", "%20", $tmp);
echo
"$url<br>\n";
echo
"<a href=\"$url\"><b>$label</b>/</a><br>\n";
}
else
{
$link = urlFromPath ($alink);

$label = $list[$i];
echo
"<a href=\"$link\">".$label."</a><br>\n";
}
}
}
echo
"</ul>";
closedir ($handle);
}
}

?>
1
Alex Dawn
1 年前
<?php

/**
* 這些函式與生成器搭配使用效果很好,可以隱藏所有雜亂的檔案處理程式(有點像 Python 的 with 區塊)
* 移除 echo 只是為了示範生成器如何與 foreach 迴圈一起運作。
*
* @param string $filepath
* @return Generator<string>
*/
function generateFiles(string $filepath): Generator
{
echo
"開啟處理程式" . PHP_EOL;
$handle = opendir($filepath);
// 看起來比需要的複雜,但文件說類型檢查很重要
// https://php.dev.org.tw/manual/en/function.readdir.php
try {
while (
false !== ($entry = readdir($handle))) {
yield
$entry;
}
} finally {
closedir($handle);
echo
"關閉處理程式" . PHP_EOL;
}
}

foreach (
generateFiles('.') as $file) {
echo
$file . PHP_EOL;
}
2
Lasse Dalegaard
19 年前
我製作了一個函式,用於尋找指定目錄及其所有子目錄中的所有檔案。當在許多子目錄中搜尋大量檔案時,它非常有用。此函式會傳回一個包含所有找到檔案路徑的陣列。

<?
function getFiles($directory) {
// 嘗試開啟目錄
if($dir = opendir($directory)) {
// 建立一個陣列來存放所有找到的檔案
$tmp = Array();

// 加入檔案
while($file = readdir($dir)) {
// 確保檔案存在
if($file != "." && $file != ".." && $file[0] != '.') {
// 如果它是目錄,列出其中的所有檔案
if(is_dir($directory . "/" . $file)) {
$tmp2 = getFiles($directory . "/" . $file);
if(is_array($tmp2)) {
$tmp = array_merge($tmp, $tmp2);
}
} else {
array_push($tmp, $directory . "/" . $file);
}
}
}

// 結束此函式
closedir($dir);
return $tmp;
}
}

// 使用範例
print_r(getFiles('.')); // 這將會尋找目前目錄及其所有子目錄中的所有檔案
?>
1
mstabile75 at gmail dot com
18 年前
在我之前的文章中,我遇到了 $directorylist 的 "global" 定義的問題。如果我在同一個頁面上多次呼叫此函式,它會合併檔案列表。我看了 Lasse Dalegaard 的範例,並使用了以下解決方案。

移除全域定義
global $directorylist;

替換
<?
if ((($maxlevel) == "all") or ($maxlevel > $level)) {
filelist($startdir . $file . "/", $searchSubdirs, $directoriesonly, $maxlevel, $level + 1);
}
?>
改為
<?
if ((($maxlevel) == "all") or ($maxlevel > $level)) {
$list2 = filelist($startdir . $file . "/", $searchSubdirs, $directoriesonly, $maxlevel, $level + 1);
if(is_array($list2)) {
$directorylist = array_merge($directorylist, $list2);
}
}
?>
1
Peter Hkansson
16 年前
您是否想在瀏覽器中查看您的目錄?這個腳本可能對您有所幫助。

<?php
$sub
= ($_GET['dir']);
$path = 'enter/your/directory/here/';
$path = $path . "$sub";
$dh = opendir($path);
$i=1;
while ((
$file = readdir($dh)) !== false) {
if(
$file != "." && $file != "..") {
if (
substr($file, -4, -3) =="."){
echo
"$i. $file <br />";
}else{
echo
"$i. <a href='?dir=$sub/$file'>$file</a><br />";
}
$i++;
}
}
closedir($dh);
?>
1
MetaNull
17 年前
另一種以遞迴方式走訪目錄及其內容的方法,並將回呼函數應用於每個檔案。

範例:更新資料夾中每個檔案的最後修改時間

<?php

clearstatcache
();

$sourcepath = "C:/WINDOWS/TEMP";

// 將 \ 取代為 / 並移除結尾的 / (如果有的話)
$root = ereg_replace( "/$", "", ereg_replace( "[\\]", "/", $sourcepath ));
// 對 $root 目錄中的所有檔案執行 touch
if( false === m_walk_dir( $root, "m_touch_file", true )) {
echo
"'{$root}' 不是有效的目錄\n";
}

// 遞迴走訪目錄,並對每個檔案應用回呼函數
function m_walk_dir( $root, $callback, $recursive = true ) {
$dh = @opendir( $root );
if(
false === $dh ) {
return
false;
}
while(
$file = readdir( $dh )) {
if(
"." == $file || ".." == $file ){
continue;
}
call_user_func( $callback, "{$root}/{$file}" );
if(
false !== $recursive && is_dir( "{$root}/{$file}" )) {
m_walk_dir( "{$root}/{$file}", $callback, $recursive );
}
}
closedir( $dh );
return
true;
}

// 如果路徑指示檔案,則對其執行 touch()
function m_touch_file( $path ) {
echo
$path . "\n";
if( !
is_dir( $path )) {
touch( $path );
}
}

?>
1
chrys at mytechjournal dot com
18 年前
我寫了一個函數,可以從起始目錄遞迴刪除檔案。我必須這樣做,因為我的伺服器不允許我刪除 Apache 寫入的檔案,因為我沒有權限,所以... 我讓 Apache 來完成這項工作。

<?php
$dir
= "/path/to/base/dir";

recursive_delete($dir);

function
recursive_delete( $dir )
{
if (
is_dir($dir)) {
if (
$dh = opendir($dir)) {
while ((
$file = readdir($dh)) !== false ) {
if(
$file != "." && $file != ".." )
{
if(
is_dir( $dir . $file ) )
{
echo
"進入目錄:$dir$file<br/>";
recursive_delete( $dir . $file . "/" );
echo
"移除目錄:$dir$file<br/><br/>";
rmdir( $dir . $file );
}
else
{
echo
"正在刪除檔案:$dir$file<br/>";
unlink( $dir . $file );
}
}
}
closedir($dh);
}
}
}
?>
1
mana at averna dot com
16 年前
我試圖使用這個 opendir 函數來存取網路磁碟機。我讀了很多文章,說幾乎不可能存取網路磁碟機,最後,我找到了答案;要使用 PHP 在同一台或另一台機器上存取網路磁碟機,必須遵循 2 個步驟。

但首先,這是我得到的錯誤
Warning: opendir(\\server\folder1\sub_folder) [function.opendir]: failed to open dir: No error in C:\wamp\www\PMOT\v0.1\REPORT_MENU\index.php on line 17

首先,必須確保使用者(例如,具有密碼 PASS_TEST 的 USER_TEST)可以存取資料夾 \\server\folder1\sub_folder。透過設定此資料夾的屬性,可以使用正確的密碼 (USER_TEST with PASS_TEST) 加入此給定的使用者。

其次,必須設定 APACHE 服務,以將此使用者納入考量。如果未指定使用者,APACHE 會使用匿名使用者,這就是問題/錯誤訊息的來源。必須進入控制台->管理工具->服務。會看到服務列表,並且必須在描述中尋找具有 Apache/2.X.X 的 APACHE。(對於 Wampserver,它將被稱為 wampapache,以此類推!)。在此上按一下滑鼠右鍵,並彈出內容畫面。在「登入」索引標籤中,有 2 個選項:本機系統帳戶和「這個帳戶」,這將是指定的使用者帳戶。在這裡必須指定 USER_TEST 和 PASS_TEST。

遵循這些步驟對我來說效果很好,但如果停用資料夾權限或 Apache 登入使用者,則會收到前面提到的初始錯誤訊息。

無論如何,我希望這可以幫助到某人!

乾杯!

Marc
1
archipel dot gb at online dot fr
16 年前
以下是相同函數的兩個版本,用於列出目錄樹中的所有檔案。

第一個是遞迴的(在瀏覽子目錄時會自行呼叫)
<?php
function rec_listFiles( $from = '.')
{
if(!
is_dir($from))
return
false;

$files = array();
if(
$dh = opendir($from))
{
while(
false !== ($file = readdir($dh)))
{
// Skip '.' and '..'
if( $file == '.' || $file == '..')
continue;
$path = $from . '/' . $file;
if(
is_dir($path) )
$files += rec_listFiles($path);
else
$files[] = $path;
}
closedir($dh);
}
return
$files;
}
?>

第二個函式是迭代式的 (使用較少的記憶體)
<?php
function listFiles( $from = '.')
{
if(!
is_dir($from))
return
false;

$files = array();
$dirs = array( $from);
while(
NULL !== ($dir = array_pop( $dirs)))
{
if(
$dh = opendir($dir))
{
while(
false !== ($file = readdir($dh)))
{
if(
$file == '.' || $file == '..')
continue;
$path = $dir . '/' . $file;
if(
is_dir($path))
$dirs[] = $path;
else
$files[] = $path;
}
closedir($dh);
}
}
return
$files;
}
?>
迭代版本在大多數情況下應該會快一點,但最大的差異在於記憶體的使用。

這裡還有一個效能分析函式 (僅適用於 php5)
<?php
function profile( $func, $trydir)
{
$mem1 = memory_get_usage();
echo
'<pre>-----------------------
Test run for '
.$func.'() ...
'
; flush();

$time_start = microtime(true);
$list = $func( $trydir);
$time = microtime(true) - $time_start;

echo
'Finished : '.count($list).' files</pre>';
$mem2 = memory_get_peak_usage();

printf( '<pre>Max memory for '.$func.'() : %0.2f kbytes
Running time for '
.$func.'() : %0.f s</pre>',
(
$mem2-$mem1)/1024.0, $time);
return
$list;
}
?>
0
NerdyDork
17 年前
這是一個程式碼片段,用於建立一個資料夾中所有 HTML 檔案的網站地圖

<?php
// 讀取目前目錄下的所有 html 檔案
if ($dh = opendir('./')) {
$files = array();
while ((
$file = readdir($dh)) !== false) {
if (
substr($file, strlen($file) - 5) == '.html') {
array_push($files, $file);
}
}
closedir($dh);
}

// 排序檔案並顯示
sort($files);
echo
"<ul>\n";
foreach (
$files as $file) {
$title = Title($file);
echo
"<li><a href=\"$file\" title=\"$title\">$title</a></li>\n";
}
echo
"</ul>\n";

// 從檔名取得人類可讀標題的函式
function Title($filename) {
$title = substr($filename, 0, strlen($filename) - 5);
$title = str_replace('-', ' ', $title);
$title = ucwords($title);
return
$title;
}
?>
0
tim2005
18 年前
您好,

我朋友正在經營一個虛擬主機,我想我發現這個腳本有一個安全漏洞

<?php
function select_files($dir, $label = "", $select_name, $curr_val = "", $char_length = 30) {
$teller = 0;
if (
$handle = opendir($dir)) {
$mydir = ($label != "") ? "<label for=\"".$select_name."\">".$label."</label>\n" : "";
$mydir .= "<select name=\"".$select_name."\">\n";
$curr_val = (isset($_REQUEST[$select_name])) ? $_REQUEST[$select_name] : $curr_val;
$mydir .= ($curr_val == "") ? " <option value=\"\" selected>...\n" : "<option value=\"\">...\n";
while (
false !== ($file = readdir($handle))) {
$files[] = $file;
}
closedir($handle);
sort($files);
foreach (
$files as $val) {
if (
is_file($dir.$val)) { // 只顯示真實檔案 (ver. 1.01)
$mydir .= " <option value=\"".$val."\"";
$mydir .= ($val == $curr_val) ? " selected>" : ">";
$mydir .= (strlen($val) > $char_length) ? substr($val, 0, $char_length)."...\n" : $val."\n";
$teller++;
}
}
$mydir .= "</select>";
}
if (
$teller == 0) {
$mydir = "沒有檔案!";
} else {
return
$mydir;
}
}

echo
select_files("C:/winnt/", "", "", "", "60");
?>

現在我可以看到他 Windows 目錄中的歷史檔案。這是一個漏洞嗎?可以修復嗎?我也會將這個回報為錯誤!

Tim2005
0
tozeiler
18 年前
"opendir" 說
------------------------------------------------------------------

2006年1月23日 08:04
我只是想要一個目錄列表和一個可點擊的連結來下載檔案

<snip>
------
<?
echo ("<h1>目錄概覽:</h1>");

function getFiles($path) {

<snip 複雜的函式內容>

------------------------------------------------------------------
這是一個更直接的方式來將 $path/files 變成連結

<?php

echo "<h1>目錄概覽:</h1>";

$dh = opendir($path);
while ((
$file = readdir($dh)) !== false) {
echo
"<a href='$path/$file'>$file</a><br />";
}
closedir($dh);

?>
0
匿名
19 年前
此函式會依名稱字串排序檔案,但不區分大小寫。它還會對檔案大小資訊進行一些方便的字串格式化。

<?
function getFiles($path) {
//函式接受一個路徑,並回傳一個數字索引的關聯陣列,其中包含檔案資訊,
//依檔案名稱(不區分大小寫)排序。如果兩個檔案在不區分大小寫比較時相同,它們將會依readdir()提供的順序
//彼此相對排序
$files = array();
$fileNames = array();
$i = 0;

if (is_dir($path)) {
if ($dh = opendir($path)) {
while (($file = readdir($dh)) !== false) {
if ($file == "." || $file == "..") continue;
$fullpath = $path . "/" . $file;
$fkey = strtolower($file);
while (array_key_exists($fkey,$fileNames)) $fkey .= " ";
$a = stat($fullpath);
$files[$fkey]['size'] = $a['size'];
if ($a['size'] == 0) $files[$fkey]['sizetext'] = "-";
else if ($a['size'] > 1024) $files[$fkey]['sizetext'] = (ceil($a['size']/1024*100)/100) . " K";
else if ($a['size'] > 1024*1024) $files[$fkey]['sizetext'] = (ceil($a['size']/(1024*1024)*100)/100) . " Mb";
else $files[$fkey]['sizetext'] = $a['size'] . " bytes";
$files[$fkey]['name'] = $file;
$files[$fkey]['type'] = filetype($fullpath);
$fileNames[$i++] = $fkey;
}
closedir($dh);
} else die ("無法開啟目錄:$path");
} else die ("路徑不是一個目錄:$path");
sort($fileNames,SORT_STRING);
$sortedFiles = array();
$i = 0;
foreach($fileNames as $f) $sortedFiles[$i++] = $files[$f];

return $sortedFiles;
}

$files = getFiles("C:");
foreach ($files as $file) print "$file[name]<br>\n";
?>
0
iamnotanerd
19 年前
這是我建立用於搜尋檔案的程式碼片段...遞迴開啟目錄並搜尋匹配項..

<?php
function search($target, $directory){

if(
is_dir($directory)){
$direc = opendir($directory);
while(
false !== ($file = readdir($direc))){

if(
$file !="." && $file != ".."){

if(
is_file($directory."/".$file)){
if(
preg_match("/$target/i", $file)){
echo
"<a href=\"$directory/$file\">$file</a><br>";
}
}else if(
is_dir($directory."/".$file)){
search($target,$directory."/".$file);

}

}
}
closedir($direc);
}

return ;
}
?>
0
info at 4design dot nu
21 年前
除了上面關於 IIS 和 PHP 讀取網路共用磁碟的注意事項外,這裡有一個對我來說更好的解決方案。

在管理主控台中,我建立了一個我的 "read_dir" 腳本執行的資料夾。點擊屬性,然後選擇安全性標籤。在這裡,您可以將匿名帳戶設定為標準的 IUSR_$computername%,但是..在這種情況下,我選擇了另一個我設定用於讀取我的共用磁碟的帳戶。(確保登入名稱和密碼與您在遠端電腦上設定的憑證相符 ;-))

我使用這個來讀取目錄及其內容到可搜尋的資料庫中。而且它的運作效果很好...
0
Matt Grimm
21 年前
我想我可以幫助澄清一些關於在 Windows 網路(在本例中為 2000)上存取網路共用磁碟的事情,該網路在 Apache 2.0.44 下執行 PHP 4.3.2。

無論您如何登入 Windows 機器,您的 Apache 服務都必須在具有存取共享權限的帳戶下執行。對我來說,最簡單(但也可能最不安全)的方法是將 Apache 服務的使用者變更為電腦管理員(在服務屬性的「登入」標籤下執行此操作)。重新啟動 Apache 後,我就可以透過其指定的磁碟機代號(例如 "z:\\")或透過其 UNC 路徑(例如 "\\\\shareDrive\\shareDir")來存取已對應的磁碟機或一般的共享資料夾。
-2
hxss at ya dot ru
7 年前
用於處理目錄和檔案的真正遞迴式映射函式。
您可以透過可呼叫的函式來建立、讀取 (尋找)、更新 (或移動) 或刪除檔案/目錄/樹狀結構。
您可以使用標誌來選擇您需要的內容。

<?php
var_dump
(dirmap($dst, function($v) {
pre($v);
return
true;
},
1|2|4|8));

/**
* 將回呼套用至指定目錄路徑的條目
* 根據接收到的標誌
* @param string $path 工作目錄的路徑
* @param Callable $action 可呼叫的函式,將針對路徑中的每個條目執行
* @param integer $flags 可以是以下標誌:
* 1:針對檔案套用可呼叫的函式
* 2:針對目錄套用可呼叫的函式
* 4:針對 $path 套用可呼叫的函式
* 8:遞迴運作
* @return bool 所有 (bool)$action 呼叫結果的位元 AND
*/
function dirmap(string $path, Callable $action, int $flags = 15) {
$flF = boolval($flags & 1);
$flD = boolval($flags & 2);
$flP = boolval($flags & 4);
$flR = boolval($flags & 8);
$result = 1;

if (
is_dir($path)) {

$dir = opendir($path);
while (
$entry = readdir($dir))
if (!
in_array($entry, ['.', '..'])) {
$fullEntry = "{$path}/{$entry}";

if (
$flR)
$result &= dirmap($fullEntry, $action, $flags & 11);

if (
$flF && is_file($fullEntry) || $flD && is_dir($fullEntry))
$result &= (bool)call_user_func($action, $fullEntry);
}

if (
$flP)
$result &= (bool)call_user_func($action, $fullEntry);

return (bool)
$result;
} else
return
is_file($path);
}
?>
-2
frogstarr78 at yahoo dot com
17 年前
這是一個函式,它會遞迴地將目錄轉換為目錄雜湊和檔案陣列的雜湊,並自動忽略「點」檔案。

<?php
function hashify_directory($topdir, &$list, $ignoredDirectories=array()) {
if (
is_dir($topdir)) {
if (
$dh = opendir($topdir)) {
while ((
$file = readdir($dh)) !== false) {
if (!(
array_search($file,$ignoredDirectories) > -1) && preg_match('/^\./', $file) == 0) {
if (
is_dir("$topdir$file")) {
if(!isset(
$list[$file])) {
$list[$file] = array();
}
ksort($list);
hashify_directory("$topdir$file/", $list[$file]);
} else {
array_push($list, $file);
}
}
}
closedir($dh);
}
}
}
?>

例如:
<?php
$public_html
["StudentFiles"] = array();
hashify_directory("StudentFiles/", $public_html["StudentFiles"]);
?>
在目錄結構上
./StudentFiles/tutorial_01/case1/file1.html
./StudentFiles/tutorial_01/case1/file2.html
./StudentFiles/tutorial_02/case1/file1.html
./StudentFiles/tutorial_02/case2/file2.html
./StudentFiles/tutorial_03/case1/file2.html
等等...
變成
<?php
print_r
($public_html);
/*
輸出:
array(
"StudentFiles" => array (
"tutorial_01" => array (
"case1" => array( "file1.html", "file2.html")
),
"tutorial_02" => array (
"case1" => array( "file1.html"),
"case2" => array( "file2.html")
),
"tutorial_03" => array (
"case1" => array( "file2.html")
)
)
)
*/
?>
我正在使用它來建立目錄的樹狀檢視。
-2
phpguy at mailstop dot yogelements dot omitme dot com
17 年前
我遇到的一個問題是,opendir() 不會管您是否在子目錄上設定了伺服器驗證,因此以這種方式存取時,任何此類驗證都會被完全繞過。我確實為我漂亮檔案管理器的應用程式解決了這個問題,方法是將所有子目錄重新導向,如下所示:
$fdir = "./subdirectory_I_want_to_visit/";
if ($fdir != './') { //基本上我們所在的位置或是父目錄
//重新導向瀏覽器,以強制對任何子目錄進行驗證檢查
header("Location: http://my.domain.com".dirname($_SERVER["PHP_SELF"]).substr($fdir,2));
exit;
} else {
$dir = opendir($fdir);
}
-1
Madog Llwyd
15 年前
一個簡單的片段,用於開啟目錄並顯示任何具有指定副檔名的檔案。對於像電子報、記分表之類的東西來說,這非常有用,您只是想讓使用者更容易使用 - 他們只需將具有正確副檔名的檔案放入即可。會提供檔案的連結,該連結會在新的視窗中開啟。

<?php
$current_dir
= "$DOCUMENT_ROOT"."dirname/"; //放入第二部分,目錄 - 開頭沒有斜線但結尾有斜線!
$dir = opendir($current_dir); // 開啟目錄

echo ("<p><h1>可用檔案列表:</h1></p><hr><br />");
while (
$file = readdir($dir)) // while 迴圈
{
$parts = explode(".", $file); // 將檔名用句點分開
if (is_array($parts) && count($parts) > 1) { // 分割後的陣列是否有多於一個部分
$extension = end($parts); // 設定為可以看到最後的檔案副檔名
if ($extension == "ext" OR $extension == "EXT") // 副檔名是否為 ext 或 EXT ?
echo "<a href=\"$file\" target=\"_blank\"> $file </a><br />"; // 如果是,則輸出,否則不執行,因為這不是我們想要的
}
}
echo
"<hr><br />";
closedir($dir); // 完成後關閉目錄
?>
-1
kdouglas at satarah dot com
16 年前
針對檔案或目錄的廣度優先搜尋 (BFS) (相對於深度優先搜尋)
http://en.wikipedia.org/wiki/Breadth-first_search

<?php

// 針對檔案或目錄的廣度優先遞迴目錄搜尋
// 具有可選的黑名單路徑和可選的回呼函式。
//
// $root -- 是搜尋開始目錄的相對路徑
// $file -- 是限定的檔案名稱:'name.ext' EX: 'data.xml'
// (或) $file -- 是目標目錄名稱 EX: 'xml_files'
// $callback -- 是一個可選的函式名稱,並將傳遞所有匹配的路徑 EX: 'my_func',而不是在第一個匹配時退出
// $omit -- 是排除路徑的可選陣列 -- 相對於根目錄
// 若要使用 $omit 但不使用 $callback,請將 NULL 作為 $callback 參數傳遞
//
// 測試值如下 ...

function my_func ( $path ) {
print
"<strong>$path</strong><br>\n";
}

$root = '../public_html';
$file = 'data.xml';
$callback = 'my_func';
$omit = array( 'include/img', 'include/css', 'scripts' );

//print breadth_first_file_search ( $root, $file );
//print breadth_first_file_search ( $root, $file, $callback );
//print breadth_first_file_search ( $root, $file, NULL, $omit );
print breadth_first_file_search ( $root, $file, $callback, $omit );

function
breadth_first_file_search ( $root, $file, $callback = NULL, $omit = array() ) {
$queue = array( rtrim( $root, '/' ).'/' ); // 正規化所有路徑
foreach ( $omit as &$path ) { // &$path 需要 PHP 版本 5.x 及更新版本
$path = $root.trim( $path, '/' ).'/';
}
while (
$base = array_shift( $queue ) ) {
$file_path = $base.$file;
if (
file_exists( $file_path ) ) { // 找到檔案
if ( is_callable( $callback ) ) {
$callback( $file_path ); // 回呼函式 => 繼續
} else {
return
$file_path; // 傳回檔案路徑 => 退出
}
}
if ( (
$handle = opendir( $base ) ) ) {
while ( (
$child = readdir( $handle ) ) !== FALSE ) {
if (
is_dir( $base.$child ) && $child != '.' && $child != '..' ) {
$combined_path = $base.$child.'/';
if ( !
in_array( $combined_path, $omit ) ) {
array_push( $queue, $combined_path);
}
}
}
closedir( $handle );
}
// 否則無法開啟目錄 => 下一個子目錄
}
return
FALSE; // 樹的末端,找不到檔案
}

?>
-1
Anonymous
18 年前
我只是想要一個目錄列表和一個可點擊的連結來下載檔案,因為我的 Plesk 伺服器沒有提供此功能。 我稍微編輯了一下腳本。

非常感謝來自腳本新手

------
<?
echo ("<h1>目錄概覽:</h1>");

function getFiles($path) {
//函式接受一個路徑,並回傳一個數字索引的關聯陣列,其中包含檔案資訊,
//依檔案名稱(不區分大小寫)排序。如果兩個檔案在不區分大小寫比較時相同,它們將會依readdir()提供的順序
//彼此相對排序
$files = array();
$fileNames = array();
$i = 0;

if (is_dir($path)) {
if ($dh = opendir($path)) {
while (($file = readdir($dh)) !== false) {
if ($file == "." || $file == "..") continue;
$fullpath = $path . "/" . $file;
$fkey = strtolower($file);
while (array_key_exists($fkey,$fileNames)) $fkey .= " ";
$a = stat($fullpath);
$files[$fkey]['size'] = $a['size'];
if ($a['size'] == 0) $files[$fkey]['sizetext'] = "-";
else if ($a['size'] > 1024) $files[$fkey]['sizetext'] = (ceil($a['size']/1024*100)/100) . " K";
else if ($a['size'] > 1024*1024) $files[$fkey]['sizetext'] = (ceil($a['size']/(1024*1024)*100)/100) . " Mb";
else $files[$fkey]['sizetext'] = $a['size'] . " bytes";
$files[$fkey]['name'] = $file;
$files[$fkey]['type'] = filetype($fullpath);
$fileNames[$i++] = $fkey;
}
closedir($dh);
} else die ("無法開啟目錄:$path");
} else die ("路徑不是一個目錄:$path");
sort($fileNames,SORT_STRING);
$sortedFiles = array();
$i = 0;
foreach($fileNames as $f) $sortedFiles[$i++] = $files[$f];

return $sortedFiles;
}

$files = getFiles("./");
foreach ($files as $file) print "&nbsp;&nbsp;&nbsp;&nbsp;<b><a href=\"$file[name]\">$file[name]</a></b><br>\n";
?>
-1
Richard Bronosky
15 年前
取得目錄列表並排序的最簡單方法是執行 exec() 來執行 ls (例如:'ls -t')。但是,這被認為是「不安全」的。我的主機公司最終抓到我這樣做,所以這是我的最快解決方案。(幸運的是,每個檔案的名稱結尾都以 Unix 時間戳記建立,並且沒有其他數字在其中。)

<?php
#exec('ls -t ./images/motion_detection/', $files); # 他們禁止 exec,所以我現在必須手動完成。
if ($handle = opendir('./images/motion_detection/')) {
$files=array();
while (
false !== ($file = readdir($handle))) {
$files[$file] = preg_replace('/[^0-9]/', '', $file); # 時間戳記可能不是唯一的,但檔案名稱是。
}
closedir($handle);
arsort($files);
$files=array_keys($files);
}
?>

在複製別人的臃腫廚房水槽函式/類別之前,請考慮一下您擁有的東西和您真正需要的東西。
-1
micklweiss at gmx dot net
21 年前
我在範例 1 中遇到一點小問題。 opendir() 會根據上次存取檔案的時間列出檔案。我試著以數字順序列出目錄中的檔案。

解決方案:改用 scandir() (php5) 或將檔案儲存在陣列中並進行排序。

希望這對某些人有幫助。

- Mick

(o> 網頁 / 軟體開發人員
( ) UNIX 系統管理員
--- ~ www.mickweiss.com ~
-2
Anonymous
15 年前
如果您想要逐一查看目錄,請查看 SPL DirectoryIterator
https://php.dev.org.tw/manual/class.directoryiterator.php
-3
olivernassar.com
15 年前
希望這能幫助其他人。傳回目錄和任何子目錄中所有檔案的清單。
排除 $exempt 陣列中的檔案/資料夾。可以修改它,使其不以參照方式傳遞檔案,相當容易。

<?php

function getFiles($directory,$exempt = array('.','..','.ds_store','.svn'),&$files = array()) {
$handle = opendir($directory);
while(
false !== ($resource = readdir($handle))) {
if(!
in_array(strtolower($resource),$exempt)) {
if(
is_dir($directory.$resource.'/'))
array_merge($files,
self::getFiles($directory.$resource.'/',$exempt,$files));
else
$files[] = $directory.$resource;
}
}
closedir($handle);
return
$files;
}

?>
-2
lolwut
17 年前
我偶爾會覺得這段程式碼很有用。希望你也會覺得有用。

<?php
//list_by_ext: 返回一個陣列,其中包含指定目錄 ($path) 中,副檔名與 $extension 相符的檔案,並按字母順序排列

function list_by_ext($extension, $path){
$list = array(); //初始化一個變數
$dir_handle = @opendir($path) or die("無法開啟 $path"); //嘗試開啟路徑
while($file = readdir($dir_handle)){ //迴圈遍歷路徑中的所有檔案
if($file == "." || $file == ".."){continue;} //忽略這些
$filename = explode(".",$file); //將檔名與副檔名分開
$cnt = count($filename); $cnt--; $ext = $filename[$cnt]; //如上
if(strtolower($ext) == strtolower($extension)){ //如果檔案的副檔名與我們正在尋找的副檔名相符...
array_push($list, $file); //...然後將其添加到列表陣列的末尾
}
}
if(
$list[0]){ //...如果找到匹配的檔案...
return $list; //...返回陣列
} else {//否則...
return false;
}
}

//使用範例
if($win32_exectuables = list_by_ext("exe", "C:\WINDOWS")){
var_dump($win32_exectuables);
} else {
echo
"找不到 Windows 可執行檔 :(\n";
}

?>
-3
php at uchange dot co dot uk
16 年前
在花了一個小時左右試圖從 Windows 上的網路共享取得完整的檔案列表後,我放棄了(Apache 2.2 Win32,WinXP,PHP5 -> Windows 2000 R2)。

嘗試使用對應的磁碟機代號會出現錯誤,而嘗試使用 UNC 路徑雖然可行,但速度非常慢(開啟並使用 readdir() 讀取一個有幾百個檔案的目錄需要幾分鐘)。

使用這段程式碼速度很快且立即完成(你必須自己處理輸出,但就這樣吧!)

$out = `dir $dir /B /S`;

如果你不需要遞迴子目錄,請從命令中移除 /S - 如需更多詳細資訊,請在 Windows 上執行 'dir /?'。

希望這能幫助遇到類似問題的人!
-2
mstabile75 at gmail dot com
18 年前
<?php
/* 以下函式將列出目錄中的所有資料夾和檔案
它是一個使用全域陣列的遞迴函式。全域陣列對我來說是在遞迴函式中使用陣列最簡單的方法
*此函式對您可以搜尋的層級數沒有限制。
*此陣列結構對我來說很有效。
參數:
$startdir => 指定起始目錄;格式:必須以「/」結尾
$searchSubdirs => True/false;如果要搜尋子目錄,則為 True
$directoriesonly => True/false;如果只想回傳目錄,則為 True
$maxlevel => "all" 或數字;指定要搜尋的目錄層級數
$level => 整數;函式目前正在搜尋的目錄層級
*/
function filelist ($startdir="./", $searchSubdirs=1, $directoriesonly=0, $maxlevel="all", $level=1) {
//列出您要忽略的目錄/檔案名稱
$ignoredDirectory[] = ".";
$ignoredDirectory[] = "..";
$ignoredDirectory[] = "_vti_cnf";
global
$directorylist; //初始化全域陣列
if (is_dir($startdir)) {
if (
$dh = opendir($startdir)) {
while ((
$file = readdir($dh)) !== false) {
if (!(
array_search($file,$ignoredDirectory) > -1)) {
if (
filetype($startdir . $file) == "dir") {
//以您選擇的方式建立您的目錄陣列;
//加入您想要的其他檔案詳細資訊。
$directorylist[$startdir . $file]['level'] = $level;
$directorylist[$startdir . $file]['dir'] = 1;
$directorylist[$startdir . $file]['name'] = $file;
$directorylist[$startdir . $file]['path'] = $startdir;
if (
$searchSubdirs) {
if (((
$maxlevel) == "all") or ($maxlevel > $level)) {
filelist($startdir . $file . "/", $searchSubdirs, $directoriesonly, $maxlevel, $level + 1);
}
}
} else {
if (!
$directoriesonly) {
//如果要包含檔案;建立您的檔案陣列
//以您選擇的方式;加入您想要的其他檔案詳細資訊。
$directorylist[$startdir . $file]['level'] = $level;
$directorylist[$startdir . $file]['dir'] = 0;
$directorylist[$startdir . $file]['name'] = $file;
$directorylist[$startdir . $file]['path'] = $startdir;
}}}}
closedir($dh);
}}
return(
$directorylist);
}
$files = filelist("./",1,1); // 呼叫函式
foreach ($files as $list) {//列印陣列
echo "Directory: " . $list['dir'] . " => Level: " . $list['level'] . " => Name: " . $list['name'] . " => Path: " . $list['path'] ."<br>";
}
?>
-5
Michael mt1955 (a) gmail.com
17 年前
# 使用回呼函式的簡單目錄遍歷

<?php
function callbackDir($dir)
{
# 在此處執行任何您想執行的操作
echo "$dir\n";
}

function
walkDir($dir,$fx)
{
$arStack = array();
$fx($dir);
if( (
$dh=opendir($dir)) )
{ while( (
$file=readdir($dh))!==false )
{ if(
$file=='.' || $file=='..' ) continue;
if(
is_dir("$dir/$file") )
{ if( !
in_array("$dir/$file",$arStack) ) $arStack[]="$dir/$file";
}
}
closedir($dh);
}
if(
count($arStack) )
{ foreach(
$arStack as $subdir )
{
walkDir($subdir,$fx);
}
}
}

walkDir($root,callBackDir);
?>
To Top