• 首页
  • vue
  • TypeScript
  • JavaScript
  • scss
  • css3
  • html5
  • php
  • MySQL
  • redis
  • jQuery
  • opendir()

    (PHP 4, PHP 5, PHP 7)

    打开目录句柄

    说明

    opendir(string $path[,resource $context]): resource

    打开一个目录句柄,可用于之后的closedir(),readdir()和rewinddir()调用中。

    参数

    $path

    要打开的目录路径

    $context

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

    返回值

    如果成功则返回目录句柄的resource,失败则返回FALSE

    如果$path不是一个合法的目录或者因为权限限制或文件系统错误而不能打开目录,opendir()返回FALSE并产生一个E_WARNING级别的 PHP 错误信息。可以在opendir()前面加上“@”符号来抑制错误信息的输出。

    更新日志

    版本说明
    5.0.0$path支持ftp://URL wrapper
    4.3.0$path可以是任何支持目录列表的 URL,不过在 PHP 4 中只有file://URL wrapper 支持此功能

    范例

    Example #1opendir()例子

    <?php
    $dir = "/etc/php5/";
    // Open a known directory, and proceed to read its contents
    if (is_dir($dir)) {
        if ($dh = opendir($dir)) {
            while (($file = readdir($dh)) !== false) {
                echo "filename: $file : filetype: " . 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 类实例
    Sometimes the programmer needs to access folder content which has arabic name but the opendir function will return null resources id
    for that we must convert the dirname charset from utf-8 to windows-1256 by the iconv function just if the preg_match function detect arabic characters and use " U " additionality to enable multibyte matching
    <?php
    $dir = ("./"); // on this file dir
       
    // detect if the path has arabic characters and use " u " optional to enable function to match multibyte characters
    if (preg_match('#[\x{0600}-\x{06FF}]#iu', $dir) ) 
    {
      // convert input ( utf-8 ) to output ( windows-1256 ) 
      
      $dir = iconv("utf-8","windows-1256",$dir);
      
    }
     if( is_dir($dir) ) 
     {
       
       
       if( ( $dh = opendir($dir) ) !== null ) 
       {
      
         
         while ( ( $file = readdir($dh) ) !== false ) 
         {
           
           
           echo "filename: ".$file ." filetype : ".filetype($dir.$file)."<br/>";
           
           
         }
        
       }
       
       
     }
    ?>
    
    iterated function that searches a folder or file in a directory.
    <?php
    $root = '../Classes';
    $search_parameter = "CachedObjectStorageFactory.php";
    //if we call the function spider as spider($root); 
    //will show all the directory content including subdirectories
    //if we call the function spider as spider('../Classes', 'Shared');
    //and will show the address of the directory
    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);
         
       }  
      }
      
    }   
    ?>
    
    Here is a snippet to create a site map of all html files in a folder:
    <?php
      // read all html file in the current directory
      if ($dh = opendir('./')) {
        $files = array();
        while (($file = readdir($dh)) !== false) {
          if (substr($file, strlen($file) - 5) == '.html') {
            array_push($files, $file);
          }
        }
        closedir($dh);
      }
      
      // Sort the files and display
      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 to get a human readable title from the filename
      function Title($filename) {
        $title = substr($filename, 0, strlen($filename) - 5);
        $title = str_replace('-', ' ', $title);
        $title = ucwords($title);
        return $title;
      }
    ?>
    
    Here are two versions of the same function to list all files in a directory tree.
    The first one is recursive (calls itself while going through subdirectories) :
    <?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;
    }
    ?>
    The second one is iterative (uses less memory) :
    <?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;
    }
    ?>
    The iterative version should be a little faster most of the time, but the big difference is in the memory usage.
    Here is also a profiling function (works in php5 only) :
    <?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;
    }
    ?>
    
    A couple of notes on Matt's posts on Windows Network Drives:
    Since the system() command writes the output of the executed shell command straight to the output buffer, if you wish to hide the return of the mapping command (i.e. "The command completed succesfully" or an error message) from a web browser, you need to alter the command that is sent to the shell so that the output of that command is hidden.
    You probably thinking "why not just use exec()?", and it's a reasonable question, but for some reason it doesn't always work - I guess it's another NT user permissions issue. If you want to guarantee you app will work with no messing around on the host system, use the system() command.
    In the Windows command shell, you can hide the output of a command by sending both the output (1) and error (2) messages to "nul" using pipes, in other words ">nul 2>&1" on the end of the command. The username and password order in the "net use..." command needs switching in Matt's post.
    Here (http://networkm.co.uk/static/drive.html) is a function I wrote to dynamically choose which drive letter to use, based on what is currently mapped and accessible to PHP.
    <?php
    // Define the parameters for the shell command
    $location = "\\servername\sharename";
    $user = "USERNAME";
    $pass = "PASSWORD";
    $letter = "Z";
    // Map the drive
    system("net use ".$letter.": \"".$location."\" ".$pass." /user:".$user." /persistent:no>nul 2>&1");
    // Open the directory
    $dir = opendir($letter.":/an/example/path")
    ...
    ?>
    
    I sometimes find this useful. Hope you will too.
    <?php
    //list_by_ext: returns an array containing an alphabetic list of files in the specified directory ($path) with a file extension that matches $extension
    function list_by_ext($extension, $path){
      $list = array(); //initialise a variable
      $dir_handle = @opendir($path) or die("Unable to open $path"); //attempt to open path
      while($file = readdir($dir_handle)){ //loop through all the files in the path
        if($file == "." || $file == ".."){continue;} //ignore these
        $filename = explode(".",$file); //seperate filename from extenstion
        $cnt = count($filename); $cnt--; $ext = $filename[$cnt]; //as above
        if(strtolower($ext) == strtolower($extension)){ //if the extension of the file matches the extension we are looking for...
          array_push($list, $file); //...then stick it onto the end of the list array
        }
      }
      if($list[0]){ //...if matches were found...
      return $list; //...return the array
      } else {//otherwise...
      return false;
      }
    }
    //example usage
    if($win32_exectuables = list_by_ext("exe", "C:\WINDOWS")){
      var_dump($win32_exectuables);
    } else {
      echo "No windows executables found :(\n";
    }
    ?>
    
    This function sorts files by name as strings, but without regard to case. It also does some handy string formatting of the file size information.
    <?
    function getFiles($path) {
      //Function takes a path, and returns a numerically indexed array of associative arrays containing file information,
      //sorted by the file name (case insensitive). If two files are identical when compared without case, they will sort
      //relative to each other in the order presented by 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 ("Cannot open directory: $path");
      } else die ("Path is not a directory: $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";
    ?>
    
    A simple piece to open a directory and display any files with a given extension. Great for things like newsletters, score sheets or the like where you just want to make it easy on the user - they just dump in the file with the correct extension and it's done. A link is given to the file which opens up in a new window.
    <?php
     $current_dir = "$DOCUMENT_ROOT"."dirname/";  //Put in second part, the directory - without a leading slash but with a trailing slash!
     $dir = opendir($current_dir);    // Open the sucker
     
     echo ("<p><h1>List of available files:</h1></p><hr><br />");
     while ($file = readdir($dir))      // while loop
      {
      $parts = explode(".", $file);          // pull apart the name and dissect by period
      if (is_array($parts) && count($parts) > 1) {  // does the dissected array have more than one part
        $extension = end($parts);    // set to we can see last file extension
        if ($extension == "ext" OR $extension == "EXT")  // is extension ext or EXT ?
           echo "<a href=\"$file\" target=\"_blank\"> $file </a><br />";  // If so, echo it out else do nothing cos it's not what we want
        }
      }
     echo "<hr><br />";
     closedir($dir);    // Close the directory after we are done
    ?>
    
    I was trying to access network drives using this opendir function. I read so many posts saying that it was almost impossible to access a network drive and finally, I found the answer; there are 2 steps to be followed to access a network drive with PHP either on the same machine or another machine.
    But first of all, here's the error I was getting:
    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
    Firstly, one must make sure that the folder \\server\folder1\sub_folder can be accessed by a user, let's say USER_TEST with a password PASS_TEST. By setting properties to this folder, one can add this given user with the correct password (USER_TEST with PASS_TEST).
    Secondly, the APACHE service must be set-up to take this user into account. If no user is specified, APACHE uses an anonymous user and this is where the problem/error message is coming from. One must go in control panel->administrative tools->services. One will see the list of services and must look for APACHE with Apache/2.X.X in the description. (For Wampserver, it will be called wampapache, and so on!) Right click on that and pop up the properties screen. In the tab LOG ON, there are 2 options: local system account and "this account" which will be a user specified account. This is where one must specify the USER_TEST and PASS_TEST.
    Following these steps worked perfectly for me but if either the folder privileges or apache log on user is disabled, then I get the initial aforementioned error message.
    Anyways, I hope this can help out someone!
    Cheers!
    Marc
    Hopefully this helps someone else. Returns a list of all the files in the directory and any subdirectories.
    Excludes files/folders that are in the $exempt array. Can modifiy it so files aren't passed by reference fairly easily.
    <?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;
      }
    ?>
    
    An other way to recursively walk a directory and it's content, applying a callback to each file.
    Exemple: Update the last modification time of each file in a folder
    <?php
    clearstatcache();
    $sourcepath = "C:/WINDOWS/TEMP";
    // Replace \ by / and remove the final / if any
    $root = ereg_replace( "/$", "", ereg_replace( "[\\]", "/", $sourcepath ));
    // Touch all the files from the $root directory
    if( false === m_walk_dir( $root, "m_touch_file", true )) {
      echo "'{$root}' is not a valid directory\n";
    }
    // Walk a directory recursivelly, and apply a callback on each file
    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;
    }
    // if the path indicates a file, run touch() on it
    function m_touch_file( $path ) {
      echo $path . "\n";
      if( !is_dir( $path )) {
        touch( $path );
      }
    }
    ?>
    
    In my previous post I ran into a problem with the "global" definition of $directorylist. If I called the function more than once on the same page it would combine the file lists. I looked at Lasse Dalegaard's example and used the following solution.
    remove global definition
       global $directorylist; 
    REPLACE 
    <?
    if ((($maxlevel) == "all") or ($maxlevel > $level)) {
      filelist($startdir . $file . "/", $searchSubdirs, $directoriesonly, $maxlevel, $level + 1);
    }
    ?>
    WITH
    <?
    if ((($maxlevel) == "all") or ($maxlevel > $level)) {
      $list2 = filelist($startdir . $file . "/", $searchSubdirs, $directoriesonly, $maxlevel, $level + 1);
      if(is_array($list2)) {
        $directorylist = array_merge($directorylist, $list2);
      }
    }
    ?>
    
    "opendir" said:
    ------------------------------------------------------------------
    23-Jan-2006 08:04
    I Just wanted a directory list and a clickable link to download the files 
    <snip>
    ------
    <?
    echo ("<h1>Directory Overzicht:</h1>");
    function getFiles($path) {
    <snip complicated function contents>
    ------------------------------------------------------------------
    Here's a more straightforward way to linkify $path/files:
    <?php
    echo "<h1>Directory Overzicht:</h1>";
    $dh = opendir($path);
    while (($file = readdir($dh)) !== false) {
      echo "<a href='$path/$file'>$file</a><br />";
    }
    closedir($dh);
    ?>
    
    I wrote a function to recursively delete files from a starting directory. I had to do this because my server doesn't allow me to delete files that apache writes because I don't have permissions, so... I let apache do the work.
    <?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 "Entering Directory: $dir$file<br/>";
                        recursive_delete( $dir . $file . "/" );
                        echo "Removing Directory: $dir$file<br/><br/>";
                        rmdir( $dir . $file );
                    }
                    else
                    {
                        echo "Deleting file: $dir$file<br/>";
                        unlink( $dir . $file );
                    }
                }
            }
            closedir($dh);
          }
        }
    }
    ?>
    
    I made a function for finding all files in a specified directory and all subdirectories. It can be quite usefull when searching in alot of files in alot subdirectories. The function returns an array with the path of all the files found.
    <?
    function getFiles($directory) {
      // Try to open the directory
      if($dir = opendir($directory)) {
        // Create an array for all files found
        $tmp = Array();
        // Add the files
        while($file = readdir($dir)) {
          // Make sure the file exists
          if($file != "." && $file != ".." && $file[0] != '.') {
            // If it's a directiry, list all files within it
            if(is_dir($directory . "/" . $file)) {
              $tmp2 = getFiles($directory . "/" . $file);
              if(is_array($tmp2)) {
                $tmp = array_merge($tmp, $tmp2);
              }
            } else {
              array_push($tmp, $directory . "/" . $file);
            }
          }
        }
        // Finish off the function
        closedir($dir);
        return $tmp;
      }
    }
    // Example of use
    print_r(getFiles('.')); // This will find all files in the current directory and all subdirectories
    ?>
    
    Here is a snippet of the code that I created to search for a file..recursively open the directories and search for a match..
    <?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 ;
    }
    ?>
    
    The TRUE recursive map function for working with dirs & files.
    You can create, read(find), update(or move) or delete files/dirs/tree by your callable function.
    You can use flags for select what content you need.
    <?php
    var_dump(dirmap($dst, function($v) {
      pre($v);
      return true;
    }, 1|2|4|8));
    /**
     * Applies the callback to the entries of the given dir path
     * In accordance with the received flags
     * @param string  $path  path of the working directory
     * @param Callable $action Callable function that would be
     *   executed for every entry in path
     * @param integer $flags can be the following flag:
     *   1: apply Callable function for files
     *   2: apply Callable function for directories
     *   4: apply Callable function for $path
     *   8: work recursively
     * @return bool bitwise AND of all (bool)$action calls results
     */
    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);
    }
    ?>
    
    In addition to notes above about IIS & PHP reading network shares, here's one solution that works better for me.
    in the management console I created a folder where my "read_dir" script runs. click on properties then select the security tab. here you can set the anonymous account to the standard IUSR_$computername% , BUT.. in this case I chose another account that I set up for reading my shares. (make sure login name and password match the credantials you set on the remote machin ;-))
    I use this to read a dir and it's contents into a searchable database. and it works like a charm...
    Breadth-first-search (BFS) for a file or directory (vs. Depth-first-search)
    http://en.wikipedia.org/wiki/Breadth-first_search
    <?php
    // Breadth-First Recursive Directory Search, for a File or Directory
    // with optional black-list paths and optional callback function.
    //
    // $root -- is the relative path to the start-of-search directory
    // $file -- is the qualified file name: 'name.ext' EX: 'data.xml'
    //  (or) $file -- is the target directory name EX: 'xml_files'
    // $callback -- is an optional function name and will be passed all
    //  matching paths EX: 'my_func', instead of exiting on first match
    // $omit -- is an optional array of exclude paths -- relative to root
    //  To use $omit but not $callback, pass NULL as the $callback argument
    //
    // TESTING VALUES FOLLOW ...
    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, '/' ).'/' ); // normalize all paths
     foreach ( $omit as &$path ) { // &$path Req. PHP ver 5.x and later
      $path = $root.trim( $path, '/' ).'/';
     }
     while ( $base = array_shift( $queue ) ) {
      $file_path = $base.$file;
      if ( file_exists( $file_path ) ) { // file found
       if ( is_callable( $callback ) ) {
        $callback( $file_path ); // callback => CONTINUE
       } else {
        return $file_path; // return file-path => EXIT
       }
      }
      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 );
      } // else unable to open directory => NEXT CHILD
     }
     return FALSE; // end of tree, file not found
    }
    ?>
    
    Would you like to view your directories in your browser this script might come in handy.
    <?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);
    ?>
    
    Here's a function that will recrusively turn a directory into a hash of directory hashes and file arrays, automatically ignoring "dot" files. 
    <?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);
        }
      }
    }
    ?>
    e.g.
    <?php
    $public_html["StudentFiles"] = array();
    hashify_directory("StudentFiles/", $public_html["StudentFiles"]);
    ?>
    on the directory structure: 
    ./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
    etc...
    becomes:
    <?php
    print_r($public_html); 
    /*
    outputs:
    array(
     "StudentFiles" => array (
        "tutorial_01" => array (
           "case1" => array( "file1", "file2")
        ),
        "tutorial_02" => array (
           "case1" => array( "file1"),
           "case2" => array( "file2")
        ),
        "tutorial_03" => array (
           "case1" => array( "file2")
        )
     )
    )
    */
    ?>
    I'm using it to create a tree view of a directory.
    Hello,
    A friend of mine is running a webhost, I think i found a security leak with this script:
    <?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)) { // show only real files (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 = "No files!";
      } else {
        return $mydir;
      }
    }
    echo select_files("C:/winnt/", "", "", "", "60");
    ?> 
    Now i can see hist files in his windows dir. Is this a leak? and is it fixable? I'll report this as bug too!
    Tim2005
    I Just wanted a directory list and a clickable link to download the files because my plesk server does not give me this function. I edited the script a little bit.
    Many thanks from a script-noob
    ------
    <?
    echo ("<h1>Directory Overzicht:</h1>");
    function getFiles($path) {
      //Function takes a path, and returns a numerically indexed array of associative arrays containing file information,
      //sorted by the file name (case insensitive). If two files are identical when compared without case, they will sort
      //relative to each other in the order presented by 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 ("Cannot open directory: $path");
      } else die ("Path is not a directory: $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";
    ?>
    
    <?php
    /* The below function will list all folders and files within a directory
    It is a recursive function that uses a global array. The global array was the easiest 
    way for me to work with an array in a recursive function
    *This function has no limit on the number of levels down you can search.
    *The array structure was one that worked for me.
    ARGUMENTS:
    $startdir => specify the directory to start from; format: must end in a "/"
    $searchSubdirs => True/false; True if you want to search subdirectories
    $directoriesonly => True/false; True if you want to only return directories
    $maxlevel => "all" or a number; specifes the number of directories down that you want to search
    $level => integer; directory level that the function is currently searching
    */
    function filelist ($startdir="./", $searchSubdirs=1, $directoriesonly=0, $maxlevel="all", $level=1) {
      //list the directory/file names that you want to ignore
      $ignoredDirectory[] = "."; 
      $ignoredDirectory[] = "..";
      $ignoredDirectory[] = "_vti_cnf";
      global $directorylist;  //initialize global array
      if (is_dir($startdir)) { 
        if ($dh = opendir($startdir)) { 
          while (($file = readdir($dh)) !== false) {
            if (!(array_search($file,$ignoredDirectory) > -1)) {
             if (filetype($startdir . $file) == "dir") {
                //build your directory array however you choose; 
                //add other file details that you want.
                $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) {
                  //if you want to include files; build your file array 
                  //however you choose; add other file details that you want.
                 $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); // call the function
    foreach ($files as $list) {//print array
      echo "Directory: " . $list['dir'] . " => Level: " . $list['level'] . " => Name: " . $list['name'] . " => Path: " . $list['path'] ."<br>";
    }?>
    
    <?php
    /*
    ** This recursive file lister only slurps in one page at time,
    ** so it doesn't take forever to load when operating over
    ** a large system.....comes with an "Up" link for every page too.
    */
    $PHP_SELF = $_SERVER['PHP_SELF'];
    $DOCUMENT_ROOT = $_SERVER['DOCUMENT_ROOT'];
    # activate the next line (and deactivate the last) to
    # use this script in a $DOCUMENT_ROOT/~anybody
    # environment.
    #$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>Up</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);
      }
    }
    ?>
    
    I ran into a little snag in example 1. opendir() lists files by the last time the file was accessed. I was trying to print the files numerically in a directory. 
    Solution: Use scandir() instead (php5) or store the files in an array and sort it.
    Hope this helps someone. 
    - Mick
    (o> Web / software developer 
    ( )   UNIX Systems Admin
    ---  ~ www.mickweiss.com ~
    Thought I could help clarify something with accessing network shares on a Windows network (2000 in this case), running PHP 4.3.2 under Apache 2.0.44.
    However you are logged into the Windows box, your Apache service must be running under an account which has access to the share. The easiest (and probably least safe) way for me was to change the user for the Apache service to the computer administrator (do this in the service properties, under the "Log On" tab). After restarting Apache, I could access mapped drives by their assigned drive letter ("z:\\") or regular shares by their UNC path ("\\\\shareDrive\\shareDir").
    # simple directory walk with callback function
    <?php
    function callbackDir($dir)
    { 
      # do whatever you want here
      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);
    ?>
    
    An issue that I ran into is that opendir() could care less if you've got server authentication set on sub directories and so any such authentication is bypassed completely when accesses in this way. I did solve it for my application of a pretty file manager, by redirecting to all sub directories thusly:
    $fdir = "./subdirectory_I_want_to_visit/";
    if ($fdir != './') { //basically where we are or the parent
      //redirect the browser to force authentication check on any subdirectories
      header("Location: http://my.domain.com".dirname($_SERVER["PHP_SELF"]).substr($fdir,2));
      exit;
    } else {
      $dir = opendir($fdir);
    }
    Having spent an hour or so trying to get a complete list of files from a network share on Windows, I've given up (Apache 2.2 Win32, WinXP, PHP5 -> Windows 2000 R2).
    Trying to use a mapped drive letter gives me an error and trying to use the UNC path works but is dog slow (it takes a couple of minutes to open and readdir() a directory with a couple of hundred files).
    Using this code is fast and instant (you'll have to chop up the output yourself but so be it!)
    $out = `dir $dir /B /S`;
    If you don't need recursive subdirectories remove the /S from the command - for more details run 'dir /?' on Windows.
    Hope this helps somebody in a similar fix!
    If you want to iterate through a directory, have a look at the SPL DirectoryIterator:
    http://php.net/manual/class.directoryiterator.php
    The easiest way to get a dir listing and sort it is to exec() out to ls (eg:'ls -t'). But, that is considered "unsafe". My hosting company finally caught me doing it so here is my fastest solution. (Lucky for me each file is created with a Unix Timestamp at the end of the name and no other numbers in it.)
    <?php
    #exec('ls -t ./images/motion_detection/', $files); # They outlawed exec, so now I have to do it by hand.
    if ($handle = opendir('./images/motion_detection/')) {
      $files=array();
      while (false !== ($file = readdir($handle))) {
        $files[$file] = preg_replace('/[^0-9]/', '', $file); # Timestamps may not be unique, file names are.
      }
      closedir($handle);
      arsort($files);
      $files=array_keys($files);
    }
    ?>
    Before you go copying someone's bloat kitchen sink function/class, consider what you have and what you really need.

    上篇:getcwd()

    下篇:readdir()