Remove folders from php scandir listing - php

I have a php script $filelist = scandir('myfolder/') which list outs files from my folder. But it is adding child folders also to the array so that they are also populated when i print the result using foreach. I want to remove folders from getting added to the array. How can I do this??

Simple way
$dir = 'myfolder/';
$filelist = scandir($dir);
foreach ($filelist as $key => $link) {
if(is_dir($dir.$link)){
unset($filelist[$key]);
}
}

A clean concise solution could be to use array_filter to exclude all sub-directories like this
$files = array_filter(scandir('directory'), function($item) {
return !is_dir('directory/' . $item);
});
This effectively also removes the . and .. which represent the current and the parent directory respectively.

You can use the function glob(), and check if the item of array is_dir().

If you know what the name of the folders are, you could create an array of these folders and then use array_diff to remove them from the result:
$folders = array('..', '.', 'folder');
$files = array_diff(scandir($dir), $folders);

scandir returns an array of folders. You can remove any element of the array like this:
unset( $filelist[0] );
where 0 is the index of the element you wish to remove. You can also use array_search() if you need to find directories by name.

try
<?php
$dir = "/example";
$filelist = new Array();
if (is_dir($dir)) {
if ($dh = opendir($dir)) {
while (($file = readdir($dh)) !== false) {
if (!is_dir($file)) {
$filelist[] = $file;
}
}
closedir($dh);
}
}
?>
It's like doing a scandir, but checking the type of the returned files

Related

Codeigniter list only files non-recursively

I'd like to list the names of files from a specific location, without names of the subdirectories and files they may contain.
I've used CI's directory_map function with a success, but had to make a small workaround to get rid of the folder names in not quite a neat way:
$files = directory_map('src/img/example/', 1);
foreach($files as $i => $file) {
if(strpos($file, '\\') !== false) {
unset($files[$i]);
}
}
I'm sure there has to be a way easier and better solution, but had no luck finding it
You can get an array of filenames in a one-liner, using scandir()
http://php.net/manual/en/function.scandir.php
Here's an example that does an array_diff() to remove the "." and ".." directories.
$files = array_diff(scandir('src/img/example'), array('..', '.'));
You can also use array_filter().
$files = array_filter(scandir('src/img/example'), function($item) {
return !is_dir('directory/' . $item);
});
a possible option would be to use a DirectoryIterator
$arrFiles = [];
foreach (new DirectoryIterator('src/img/example/') as $objFile)
{
if($objFile->isFile()) $arrFiles[] = $objFile->getFilename();
}

PHP List Directories Recursively Issue

I'm trying to list all PHP files in a specified directory and for it to recursively check all sub-directories until it finds no more, there could be numerous levels.
The function I have below works fine with the exception that it only recurses down one level.
I've spent hours trying to see where I'm going wrong, I'm calling the scanFiles() when it finds a new directory but this only seems to work one level down and stop, any help greatly appreciated.
Updated:
function scanFiles($pParentDirectory)
{
$vFileArray = scandir($pParentDirectory);
$vDirectories = array();
foreach ($vFileArray as $vKey => $vValue)
{
if (!in_array($vValue, array('.', '..')) && (strpos($vValue, '.php') || is_dir($vValue)))
{
if (!is_dir($vValue))
$vDirectories[] = $vValue;
else
{
$vDirectory = $vValue;
$vSubFiles = scanFiles($vDirectory);
foreach ($vSubFiles as $vKey => $vValue)
$vDirectories[] = $vDirectory.DIRECTORY_SEPARATOR.$vValue;
}
}
}
return $vDirectories;
}
You can do this easily like this:
// helper function
function getFiles(&$files, $dir) {
$items = glob($dir . "/*");
foreach ($items as $item) {
if (is_dir($item)) {
getFiles($files, $item);
} else {
if (end(explode('.', $item)) == 'php') {
$files[] = basename($item);
}
}
}
}
// usage
$files = array();
getFiles($files, "myDir");
// debug
var_dump($files);
myDir looks like this: has php files in all dirs
Output:
P.S. if you want the function to return the full path to the found .php files, remove the basename() from this line:
$files[] = basename($item);
This will then produce result like this:
hope this helps.
This is because $vDirectory is just a folder name, so scanDir looks in the current folder for it, not the sub folder.
What you want to do is to pass in the path to the folder, not just the name. This should be as simple as changing your recursive call to scanFiles($pParentDirectory . DIRECTORY_SEPARATOR . $vDirectory)
Your main problem is functions like scanDir or isDir need the full file path to work.
If you pass the full file path to them, it should work correctly.

Iterate through a folder?

I'm looking for the best way to iterate through a folder and put all the file names inside it into an array and in another one the count of the files.
I have found glob() as a good solution, but also a lot of alternatives for it on php.net. I'm not sure which I should use, so I'm asking here. If you're wondering for what I want to use it, it's to get all the .sql files inside a backup folder and display them as <li>thesqlfile.sql</li> and have a count of all of them too.
So I thought of having two arrays, one with their names, and one with the count of all of them. So in this case which method would be best fit to iterate ?
Method I:
<?php
$files = array();
foreach (glob("backup/*.txt") as $filename) {
$files[]= $filename;
}
$count = sizeof($files);
?>
Method II:
function getfoldercontents($dir, $file_display = array(), $exclusions = array()) {
if(!file_exists($dir)){
return FALSE;
}
$dir_contents = scandir($dir);
$contents = array();
foreach ($dir_contents as $file){
$file_parts = explode('.', $file);
$file_type = strtolower(end($file_parts));
if ($file !== '.' && $file !== '..' && in_array($file_type, $file_display) && !in_array($file, $exclusions)) {
$contents[] = $dir. '/'. $file;
}
}
return $contents;
}
Since glob() already returns an array, you don't need to iterate over it to append to an array at all. Your first method is a little over-complicated. This accomplishes the same thing:
// Just assign the array output of glob() to a variable
$files = glob("backup/*.txt");
$num_files = count($files);
I would say the second is probably better in terms of file-control (through $file_display and $file_exclude), but maybe you should add a check to ensure the current file is not a directory named something.typeyouwishtodisplay

Exclude hidden files from scandir

I am using the following code to get a list of images in a directory:
$files = scandir($imagepath);
but $files also includes hidden files. How can I exclude them?
On Unix, you can use preg_grep to filter out filenames that start with a dot:
$files = preg_grep('/^([^.])/', scandir($imagepath));
I tend to use DirectoryIterator for things like this which provides a simple method for ignoring dot files:
$path = '/your/path';
foreach (new DirectoryIterator($path) as $fileInfo) {
if($fileInfo->isDot()) continue;
$file = $path.$fileInfo->getFilename();
}
$files = array_diff(scandir($imagepath), array('..', '.'));
or
$files = array_slice(scandir($imagepath), 2);
might be faster than
$files = preg_grep('/^([^.])/', scandir($imagepath));
function nothidden($path) {
$files = scandir($path);
foreach($files as $file) {
if ($file[0] != '.') $nothidden[] = $file;
return $nothidden;
}
}
Simply use this function
$files = nothidden($imagepath);
I encountered a comment from php.net, specifically for Windows systems: http://php.net/manual/en/function.filetype.php#87161
Quoting here for archive purposes:
I use the CLI version of PHP on Windows Vista. Here's how to determine if a file is marked "hidden" by NTFS:
function is_hidden_file($fn) {
$attr = trim(exec('FOR %A IN ("'.$fn.'") DO #ECHO %~aA'));
if($attr[3] === 'h')
return true;
return false;
}
Changing if($attr[3] === 'h') to if($attr[4] === 's') will check for system files.
This should work on any Windows OS that provides DOS shell commands.
I reckon because you are trying to 'filter' out the hidden files, it makes more sense and looks best to do this...
$items = array_filter(scandir($directory), function ($item) {
return 0 !== strpos($item, '.');
});
I'd also not call the variable $files as it implies that it only contains files, but you could in fact get directories as well...in some instances :)
use preg_grep to exclude files name with special characters for e.g.
$dir = "images/";
$files = preg_grep('/^([^.])/', scandir($dir));
http://php.net/manual/en/function.preg-grep.php
Assuming the hidden files start with a . you can do something like this when outputting:
foreach($files as $file) {
if(strpos($file, '.') !== (int) 0) {
echo $file;
}
}
Now you check for every item if there is no . as the first character, and if not it echos you like you would do.
Use the following code if you like to reset the array index too and set the order:
$path = "the/path";
$files = array_values(
preg_grep(
'/^([^.])/',
scandir($path, SCANDIR_SORT_ASCENDING)
));
One line:
$path = "daten/kundenimporte/";
$files = array_values(preg_grep('/^([^.])/', scandir($path, SCANDIR_SORT_ASCENDING)));
scandir() is a built-in function, which by default select hidden file as well,
if your directory has only . & .. hidden files then try selecting files
$files = array_diff(scandir("path/of/dir"),array(".","..")) //can add other hidden file if don't want to consider
I am still leaving the checkmark for seengee's solution and I would have posted a comment below for a slight correction to his solution.
His solution masks the directories(. and ..) but does not mask hidden files like .htaccess
A minor tweak solves the problem:
foreach(new DirectoryIterator($curDir) as $fileInfo) {
//Check for something like .htaccess in addition to . and ..
$fileName = $fileInfo->getFileName();
if(strlen(strstr($fileName, '.', true)) < 1) continue;
echo "<h3>" . $fileName . "</h3>";
}

Is there an easy way to read filenames in a directory and add to an array?

I have a directory: Audio/ and in that will be mp3 files only. I'm wanting to automate the process of creating links to those files. Is there a way to read a directory and add filenames within that directory to an array?
It'd be doubly cool if we could do an associative array, and have the key be the file name minus the .mp3 tag.
Any ideas?
To elaborate: I actual have several Audio/ folders and each folder contains mp3s of a different event. The event details are being pulled from a database and populating a table. That's why I'm duplicating code, because right now in each Audio/ folder, I'm having to define the filenames for the download links and define the filenames for the mp3 player.
Thank you! This will greatly simplify my code as right now I'm repeating tons of code over and over!
The SPL way is with DirectoryIterator:
$files = array();
foreach (new DirectoryIterator('/path/to/files/') as $fileInfo) {
if($fileInfo->isDot() || !$fileInfo->isFile()) continue;
$files[] = $fileInfo->getFilename();
}
And for completeness : you could use glob as well :
$files = array_filter(glob('/path/to/files/*'), 'is_file');
This will return all files (but not the folders), you can adapt it as needed.
To get just the filenames (instead of files with complete path), just add :
$files = array_map('basename', $files);
Yes: use scandir(). If you just want the name of the file without the extension, use basename() on each element in the array you received from scandir().
This should be able to do what you're looking for:
// Read files
$files = scandir($dirName);
// Filter out non-files ('.' or '..')
$files = array_filter($files, 'is_file');
// Create associative array ('filename' => 'filename.mp3')
$files = array_combine(array_map('basename', $files), $files);
Sure...I think this should work...
$files[] = array();
$dir = opendir("/path/to/Audio") or die("Unable to open folder");
while ($file = readdir($dir)) {
$cleanfile = basename($file);
$files[$cleanfile] = $file;
}
closedir($dir);
I imagine that should work...
$results = array();
$handler = opendir($directory);
while ($file = readdir($handler)) {
if ($file != "." && $file != "..") {
$results[] = $file;
}
}
closedir($handler);
this should work, if you want any files to be excluded from the array, just add them to the if statement, same for file extensions

Categories