directoryIterator has wrong "starting point" - php

I have a recursive directory iterator looking like this:
function ReadFolderDirectory($dir,$listDir= array())
{
$listDir = array();
if($handler = opendir($dir))
{
while (($sub = readdir($handler)) !== FALSE)
{
if ($sub != "." && $sub != ".." && $sub != "Thumb.db")
{
if(is_file($dir."/".$sub))
{
$listDir[] = $sub;
}elseif(is_dir($dir."/".$sub))
{
$listDir[$sub] = ReadFolderDirectory($dir."/".$sub);
}
}
}
closedir($handler);
}
return $listDir;
}
And I use it like this
$path = dirname(__FILE__);
$path = $path.'/uploadedImages/';
$dir = new DirectoryIterator($path);
$filesArray = ReadFolderDirectory($dir);
echo json_encode($filesArray);
Now when I try to set the starting point of the directory iteration, as you see I have added /uploadedImages/ to the path, but it seems to disregard that.
No matter if that is there or not, it always starts from the same directory as the php file is in, thus including also the index.php, ._index,php, and listing of course the folder uploadedImages itself.
Any thoughts what I am missing?

There is an error in your code, you have just to remove this code line :
$dir = new DirectoryIterator($path);
Explanation
opendir(String $pathToDir) // expects a String, but you pass an Object as a parameter

Related

How to read the files and directories inside the directory

Can any one please let me know how to read the directory and find what are the files and directories inside that directory.
I've tried with checking the directories by using the is_dir() function as follows
$main = "path to the directory";//Directory which is having some files and one directory
readDir($main);
function readDir($main) {
$dirHandle = opendir($main);
while ($file = readdir($dirHandle)) {
if ($file != "." && $file != "..") {
if (is_dir($file)) {
//nothing is coming here
}
}
}
}
But it is not checking the directories.
Thanks
The most easy way in PHP 5 is with RecursiveDirectoryIterator and RecursiveIteratorIterator:
$dir = '/path/to/dir';
$directoryIterator = new RecursiveDirectoryIterator($dir);
$iterator = new RecursiveIteratorIterator($directoryIterator, RecursiveIteratorIterator::CHILD_FIRST);
foreach ($iterator as $path) {
if ($path->isDir()) {
// ...
}
}
You don't need to recurse by yourself as these fine iterators handle it by themselves.
For more information about these powerful iterators see the linked documentation articles.
You have to use full path to subdirectory:
if(is_dir($main.'/'.$file)) { ... }
Use scandir
Then parse the result and eliminate '.' and '..' and is_file()
$le_map_to_search = $main;
$data_to_use_maps[] = array();
$data_to_use_maps = read_dir($le_map_to_search, 'dir');
$aantal_mappen = count($data_to_use_maps);
$counter_mappen = 1;
while($counter_mappen < $aantal_mappen){
echo $data_to_use_maps[$counter_mappen];
$counter_mappen++;
}
$data_to_use_files[] = array();
$data_to_use_files = read_dir($le_map_to_search, 'files');
$aantal_bestanden = count($data_to_use_files);
$counter_files = 1;
while($counter_files < $aantal_files){
echo $data_to_use_files [$counter_files ];
$counter_files ++;
}
Look at the reference here:
http://php.net/manual/en/function.scandir.php
Try this
$handle = opendir($directory); //Open the directory
while (false !== ($file = readdir($handle))) {
$filepath = $directory.DS.$file; //Get all files/directories in the directory
}

How can I use PHP to check if a directory is empty?

I am using the following script to read a directory. If there is no file in the directory it should say empty. The problem is, it just keeps saying the directory is empty even though there ARE files inside and vice versa.
<?php
$pid = $_GET["prodref"];
$dir = '/assets/'.$pid.'/v';
$q = (count(glob("$dir/*")) === 0) ? 'Empty' : 'Not empty';
if ($q=="Empty")
echo "the folder is empty";
else
echo "the folder is NOT empty";
?>
It seems that you need scandir instead of glob, as glob can't see unix hidden files.
<?php
$pid = basename($_GET["prodref"]); //let's sanitize it a bit
$dir = "/assets/$pid/v";
if (is_dir_empty($dir)) {
echo "the folder is empty";
}else{
echo "the folder is NOT empty";
}
function is_dir_empty($dir) {
if (!is_readable($dir)) return null;
return (count(scandir($dir)) == 2);
}
?>
Note that this code is not the summit of efficiency, as it's unnecessary to read all the files only to tell if directory is empty. So, the better version would be
function dir_is_empty($dir) {
$handle = opendir($dir);
while (false !== ($entry = readdir($handle))) {
if ($entry != "." && $entry != "..") {
closedir($handle);
return false;
}
}
closedir($handle);
return true;
}
By the way, do not use words to substitute boolean values. The very purpose of the latter is to tell you if something empty or not. An
a === b
expression already returns Empty or Non Empty in terms of programming language, false or true respectively - so, you can use the very result in control structures like IF() without any intermediate values
I think using the FilesystemIterator should be the fastest and easiest way:
// PHP 5 >= 5.3.0
$iterator = new \FilesystemIterator($dir);
$isDirEmpty = !$iterator->valid();
Or using class member access on instantiation:
// PHP 5 >= 5.4.0
$isDirEmpty = !(new \FilesystemIterator($dir))->valid();
This works because a new FilesystemIterator will initially point to the first file in the folder - if there are no files in the folder, valid() will return false. (see documentation here.)
As pointed out by abdulmanov.ilmir, optionally check if the directory exists before using the FileSystemIterator because otherwise it'll throw an UnexpectedValueException.
I found a quick solution
<?php
$dir = 'directory'; // dir path assign here
echo (count(glob("$dir/*")) === 0) ? 'Empty' : 'Not empty';
?>
use
if ($q == "Empty")
instead of
if ($q="Empty")
For a object oriented approach using the RecursiveDirectoryIterator from the Standard PHP Library (SPL).
<?php
namespace My\Folder;
use RecursiveDirectoryIterator;
class FileHelper
{
/**
* #param string $dir
* #return bool
*/
public static function isEmpty($dir)
{
$di = new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS);
return iterator_count($di) === 0;
}
}
No need to make an instance of your FileHelper whenever you need it, you can access this static method wherever you need it like this:
FileHelper::isEmpty($dir);
The FileHelper class can be extended with other useful methods for copying, deleting, renaming, etc.
There is no need to check the validity of the directory inside the method because if it is invalid the constructor of the RecursiveDirectoryIterator will throw an UnexpectedValueException which that covers that part sufficiently.
This is a very old thread, but I thought I'd give my ten cents. The other solutions didn't work for me.
Here is my solution:
function is_dir_empty($dir) {
foreach (new DirectoryIterator($dir) as $fileInfo) {
if($fileInfo->isDot()) continue;
return false;
}
return true;
}
Short and sweet. Works like a charm.
I used:
if(is_readable($dir)&&count(scandir($dir))==2) ... //then the dir is empty
Try this:
<?php
$dirPath = "Add your path here";
$destdir = $dirPath;
$handle = opendir($destdir);
$c = 0;
while ($file = readdir($handle)&& $c<3) {
$c++;
}
if ($c>2) {
print "Not empty";
} else {
print "Empty";
}
?>
Probably because of assignment operator in if statement.
Change:
if ($q="Empty")
To:
if ($q=="Empty")
# Your Common Sense
I think your performant example could be more performant using strict comparison:
function is_dir_empty($dir) {
if (!is_readable($dir)) return null;
$handle = opendir($dir);
while (false !== ($entry = readdir($handle))) {
if ($entry !== '.' && $entry !== '..') { // <-- better use strict comparison here
closedir($handle); // <-- always clean up! Close the directory stream
return false;
}
}
closedir($handle); // <-- always clean up! Close the directory stream
return true;
}
Function count usage maybe slow on big array. isset is ever faster
This will work properly on PHP >= 5.4.0 (see Changelog here)
function dir_is_empty($path){ //$path is realpath or relative path
$d = scandir($path, SCANDIR_SORT_NONE ); // get dir, without sorting improve performace (see Comment below).
if ($d){
// avoid "count($d)", much faster on big array.
// Index 2 means that there is a third element after ".." and "."
return !isset($d[2]);
}
return false; // or throw an error
}
Otherwise, using #Your Common Sense solution it's better for avoid load file list on RAM
Thanks and vote up to #soger too, to improve this answer using SCANDIR_SORT_NONE option.
Just correct your code like this:
<?php
$pid = $_GET["prodref"];
$dir = '/assets/'.$pid.'/v';
$q = count(glob("$dir/*")) == 0;
if ($q) {
echo "the folder is empty";
} else {
echo "the folder is NOT empty";
}
?>
Even an empty directory contains 2 files . and .., one is a link to the current directory and the second to the parent. Thus, you can use code like this:
$files = scandir("path to directory/");
if(count($files) == 2) {
//do something if empty
}
I use this method in my Wordpress CSV 2 POST plugin.
public function does_folder_contain_file_type( $path, $extension ){
$all_files = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $path ) );
$html_files = new RegexIterator( $all_files, '/\.'.$extension.'/' );
foreach( $html_files as $file) {
return true;// a file with $extension was found
}
return false;// no files with our extension found
}
It works by specific extension but is easily changed to suit your needs by removing "new RegexIterator(" line. Count $all_files.
public function does_folder_contain_file_type( $path, $extension ){
$all_files = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $path ) );
return count( $all_files );
}
I had a similar problem recently, although, the highest up-voted answer did not really work for me, hence, I had to come up with a similar solution. and again this may also not be the most efficient way to go about the problem,
I created a function like so
function is_empty_dir($dir)
{
if (is_dir($dir))
{
$objects = scandir($dir);
foreach ($objects as $object)
{
if ($object != "." && $object != "..")
{
if (filetype($dir."/".$object) == "dir")
{
return false;
} else {
return false;
}
}
}
reset($objects);
return true;
}
and used it to check for empty dricetory like so
if(is_empty_dir($path)){
rmdir($path);
}
You can use this:
function isEmptyDir($dir)
{
return (($files = #scandir($dir)) && count($files) <= 2);
}
The first question is when is a directory empty? In a directory there are 2 files the '.' and '..'.
Next to that on a Mac there maybe the file '.DS_Store'. This file is created when some kind of content is added to the directory. If these 3 files are in the directory you may say the directory is empty.
So to test if a directory is empty (without testing if $dir is a directory):
function isDirEmpty( $dir ) {
$count = 0;
foreach (new DirectoryIterator( $dir ) as $fileInfo) {
if ( $fileInfo->isDot() || $fileInfo->getBasename() == '.DS_Store' ) {
continue;
}
$count++;
}
return ($count === 0);
}
#Your Common Sense,#Enyby
Some improvement of your code:
function dir_is_empty($dir) {
$handle = opendir($dir);
$result = true;
while (false !== ($entry = readdir($handle))) {
if ($entry != "." && $entry != "..") {
$result = false;
break 2;
}
}
closedir($handle);
return $result;
}
I use a variable for storing the result and set it to true.
If the directory is empty the only files that are returned are . and .. (on a linux server, you could extend the condition for mac if you need to) and therefore the condition is true.
Then the value of result is set to false and break 2 exit the if and the while loop so the next statement executed is closedir.
Therefore the while loop will only have 3 circles before it will end regardless if the directory is empty or not.
$is_folder_empty = function(string $folder) : bool {
if (!is_dir($folder))
return TRUE;
// This wont work on non linux OS.
return is_null(shell_exec("ls {$folder}"));
};
$is_folder_empty2 = function(string $folder) : bool {
if (!is_dir($folder))
return TRUE;
// Empty folders have two files in it. Single dot and
// double dot.
return count(scandir($folder)) === 2;
};
var_dump($is_folder_empty('/tmp/demo'));
var_dump($is_folder_empty2('/tmp/demo'));

Enumerate files in parent directory

I have the following function that enumerates files and directories in a given folder. It works fine for doing subfolders, but for some reason, it doesn't want to work on a parent directory. Any ideas why? I imagine it might be something with PHP's settings or something, but I don't know where to begin. If it is, I'm out of luck since this is will be running on a cheap shared hosting setup.
Here's how you use the function. The first parameter is the path to enumerate, and the second parameter is a list of filters to be ignored. I've tried passing the full path as listed below. I've tried passing just .., ./.. and realpath('..'). Nothing seems to work. I know the function isn't silently failing somehow. If I manually add a directory to the dirs array, I get a value returned.
$projFolder = '/hsphere/local/home/customerid/sitename/foldertoindex';
$items = enumerateDirs($projFolder, array(0 => "Admin", 1 => "inc"));
Here's the function itself
function enumerateDirs($directory, $filterList)
{
$handle = opendir($directory);
while (false !== ($item = readdir($handle)))
{
if ($item != "." && $item != ".." && $item != "inc" && array_search($item, $filterList) === false)
{
$path = "{$directory->path}/{$item}";
if (is_dir($item))
{
$tmp['name'] = $item;
$dirs[$item] = $tmp;
unset($tmp);
}
elseif (is_file($item))
{
$tmp['name'] = $item;
$files[] = $tmp;
unset($tmp);
}
}
}
ksort($dirs, SORT_STRING);
sort($dirs);
ksort($files, SORT_STRING);
sort($files);
return array("dirs" => $dirs, "files" => $files);
}
You are mixing up opendir and dir. You also need to pass the full path (including the directory component) to is_dir and is_file. (I assume that's what you meant to do with $path.) Otherwise, the functions will look for the corresponding file system objects in the script file's directory.
Try this for a quick fix:
<?php
function enumerateDirs($directory, $filterList)
{
$handle = dir($directory);
while (false !== ($item = $handle->read()))
{
if ($item != "." && $item != ".." && $item != "inc" && array_search($item, $filterList) === false)
{
$path = "{$handle->path}/{$item}";
$tmp['name'] = $item;
if (is_dir($path))
{
$dirs[] = $tmp;
}
elseif (is_file($path))
{
$files[] = $tmp;
}
unset($tmp);
}
}
$handle->close();
/* Anonymous functions will need PHP 5.3+. If your version is older, take a
* look at create_function
*/
$sortFunc = function ($a, $b) { return strcmp($a['name'], $b['name']); };
usort($dirs, $sortFunc);
usort($files, $sortFunc);
return array("dirs" => $dirs, "files" => $files);
}
$ret = enumerateDirs('../', array());
var_dump($ret);
Note: $files or $dirs might be not set after the while loop. (There might be no files or directories.) In that case, usort will throw an error. You should check for that in some way.

dynamic formation of array with incremental depth in PHP

I want to use a function to recursively scan a folder, and assign the contents of each scan to an array.
It's simple enough to recurse through each successive index in the array using either next() or foreach - but how to dynamically add a layer of depth to the array (without hard coding it into the function) is giving me problems. Here's some pseudo:
function myScanner($start){
static $files = array();
$files = scandir($start);
//do some filtering here to omit unwanted types
$next = next($files);
//recurse scan
//PROBLEM: how to increment position in array to store results
//$next_position = $files[][][].... ad infinitum
//myScanner($start.DIRECTORY_SEPARATOR.$next);
}
any ideas?
Try something like this:
// $array is a pointer to your array
// $start is a directory to start the scan
function myScanner($start, &$array){
// opening $start directory handle
$handle = opendir($start);
// now we try to read the directory contents
while (false !== ($file = readdir($handle))) {
// filtering . and .. "folders"
if ($file != "." && $file != "..") {
// a variable to test if this file is a directory
$dirtest = $start . DIRECTORY_SEPARATOR . $file;
// check it
if (is_dir($dirtest)) {
// if it is the directory then run the function again
// DIRECTORY_SEPARATOR here to not mix files and directories with the same name
myScanner($dirtest, $array[$file . DIRECTORY_SEPARATOR]);
} else {
// else we just add this file to an array
$array[$file] = '';
}
}
}
// closing directory handle
closedir($handle);
}
// test it
$mytree = array();
myScanner('/var/www', $mytree);
print "<pre>";
print_r($mytree);
print "</pre>";
Try to use this function (and edit it for your demands):
function getDirTree($dir,$p=true) {
$d = dir($dir);$x=array();
while (false !== ($r = $d->read())) {
if($r!="."&&$r!=".."&&(($p==false&&is_dir($dir.$r))||$p==true)) {
$x[$r] = (is_dir($dir.$r)?array():(is_file($dir.$r)?true:false));
}
}
foreach ($x as $key => $value) {
if (is_dir($dir.$key."/")) {
$x[$key] = getDirTree($dir.$key."/",$p);
}
}
ksort($x);
return $x;
}
It returns sorted array of directories.

How to get rid of . and .. while scaning the folder creating an array in php?

If you scan a folder containing other folders AND files, how do you get rid of . and .. and files? How do you put in array only folders WITHOUT . and ..?
I would like to use regular expression, but I'm newbie and I can't get it right.
My code is now this but doesn't work:
if(fnmatch("\.{1,2}",$dir_array[$i]) || is_file($dir_array[$i]){
unset($dir_array[$i]);
}else{
//other code
}
You are confusing fnmatch and regular expressions in your code. To get all files and directories except the special ones, use this:
$dir_array = array_diff($dir_array, array(".", ".."));
Alternatively, if you iterate the array anyway, you can test each element like this:
foreach ($dir_array as $name) {
if (($name != "..") && ($name != ".")) {
// Do stuff on all files and directories except . ..
if (is_dir($name)) {
// Do stuff on directories only
}
}
}
In php<5.3, you can exclusively use a callback function, too:
$dir_array = array_filter($dir_array,
create_function('$n', 'return $n != "." && $n != ".." && is_dir($n);'));
(See Allain Lalonde's answer for a more verbose version)
Since php 5.3, this can be written nicer:
$dir_array = array_filter($dir_array,
function($n) {return $n != "." && $n != ".." && is_dir($n);});
Finally, combining array_filter and the first line of code of this answer yields an (insignificantly) slower, but probably more readable version:
$dir_array = array_filter(array_diff($dir_array, array(".", "..")), is_dir);
You don’t need a regular expression to test this. Just use plain string comparison:
if ($dir_array[$i] == '.' || $dir_array[$i] == '..' || is_file($dir_array[$i])) {
unset($dir_array[$i]);
}
no regex is needed, just unset() the first two values.
$d = dir($dir);
unset($d[0]);
unset($d[1]);
This may do it.
function is_not_meta_dir($file_name) {
// return true if $filename matches some pattern.
// without knowing the format of your $dir_array
return $file_name != '.' && $file_name != '..';
}
$new_dir_array = array_filter($dir_array, 'is_not_meta_dir');
I would do it like this:
$items = array();
$handle = opendir('path/to/dir');
while (($item = readdir($handle)) !== false) {
if (! in_array($item, array('.', '..'))) {
$items[] = $item;
}
}
closedir($handle);
print_r($items);
Although, I'd rather prefer DirectoryFilterDots but it's kind of rare in the available PHP distributions.
I'd do something like this (code may not work without effort since I haven't worked in PHP for years)
<?
if ($handle = opendir('/myPath'))
{
while (false !== ($file = readdir($handle)))
{
if (bool is_dir ( $file ) && substring($file,0,1) != ".")
{
$filesArray[] = $file; // this is the bit I'm not sure of the syntax for.
}
}
}
?>
EDIT misread the question - This should now add to the array all the folder names ion myPath that are not "." or ".."
$pathsArr = array();
foreach (explode($dirSeparator, $currentPath) as $path) {
if (strlen($path) && $path !== '.') {
if ($path === '..') {
// die('.....');
array_pop($pathsArr);
} else {
$pathsArr[] = $path;
}
}
}
$realpath = $winDrive . $dirSeparator . implode($dirSeparator, $pathsArr);

Categories