PHP: readdir to scandir? - php

i wonder how i can transform exactly the following piece of code to scandir instead of readdir?
$path = 'files';
//shuffle files
$count = 0;
if ($handle = opendir($path)) {
$retval = array();
while (false !== ($file = readdir($handle))) {
$ext = pathinfo($file, PATHINFO_EXTENSION);
if ($file != '.' && $file != '..' && $file != '.DS_Store' &&
$file != 'Thumbs.db') {
$retval[$count] = $file;
$count = $count + 1;
} else {
//no proper file
}
}
closedir($handle);
}
shuffle($retval);

scandir returns, quoting :
Returns an array of filenames on
success, or FALSE on failure.
Which means you'll get the full list of files in a directory -- and can then filter those, using either a custom-made loop with foreach, or some filtering function like array_filter.
Not tested, but I suppose something like this should to the trick :
$path = 'files';
if (($retval = scandir($path)) !== false) {
$retval = array_filter($retval, 'filter_files');
shuffle($retval);
}
function filter_files($file) {
return ($file != '.' && $file != '..' && $file != '.DS_Store' && $file != 'Thumbs.db');
}
Basically, here :
First, you get the list of files, using scandir
Then, you filter out the ones you dn't want, using array_filter and a custom filtering function
Note : this custom filtering function could have been written using an anonymous function, with PHP >= 5.3
And, finally, you shuffle the resulting array.

Not sure why you want to do that, here's a much more concise solution though:
$path = 'files';
$files = array();
foreach (new DirectoryIterator($path) as $fileInfo) {
if($fileInfo->isDot() || $fileInfo->getFilename() == 'Thumbs.db') continue;
$files[] = $fileInfo->getFilename();
}
shuffle($files);

To get started with such problems always consult the PHP manual and read the comments, it's always very helpful. It states that scandir returns an array, so you can walk through it with foreach.
In order to be able to delete some entries of the array, here's an example with for:
$exclude = array( ".", "..", ".DS_Store", "Thumbs.db" );
if( ($dir = scandir($path)) !== false ) {
for( $i=0; $i<count($dir); $i++ ) {
if( in_array($dir[$i], $exclude) )
unset( $dir[$i] );
}
}
$retval = array_values( $dir );
Also have a look at the SPL iterators PHP provides, especially RecursiveDirectoryIterator and DirectoryIterator.

Here's a little function to scan a directory without getting the annoying files.
function cleanscandir ($dir) {
$list = [];
$junk = array('.', '..', 'Thumbs.db', '.DS_Store');
if (($rawList = scandir($dir)) !== false) {
foreach (array_diff($rawList, $junk) as $value) {
$list[] = $value;
}
return $list;
}
return false;
}
Outputs an array or false just like scandir does

Related

Recursivly get all files in a directory, and sub directories by extension

I was looking at RecursiveDirectoryIterator and glob to say
"return me a list of files (in an array) based on the extension (for example) .less. Oh and look in all child, grandchild and so on and so forth, excluding . and .. until you find all files matching."
But I am not sure the best approach to create a recursive function that keeps going well beyond the grand child.
What I have is a mess, its worked for two years - but now I need to refactor and change it up:
public function get_directory_of_files($path, $filename, $extension) {
if (!is_dir($path)) {
throw new AisisCore_FileHandling_FileException("Could not find said path: " . $path);
}
if (file_exists($filename)) {
$handler = opendir($path);
while ($file = readdir($handler)) {
if ($file != "." && $file != "..") {
$this->package_files [] = $file;
$count = count($this->package_files);
for ($i = 0; $i < $count; $i++) {
if (substr(strrchr($this->package_files [$i], '.'), 1) == $extension) {
if ($this->package_files [$i] == $filename) {
$this->files_got_back = $this->package_files [$i];
}
}
}
}
}
}
return $this->_files_got_back;
}
This requires a file name to be passed in and thats not really my thing to do any more. So how can I re-write this function to do the above "pseudo code"
This function recursively finds files with a matching ending string
function getDirectoryContents($directory, $extension)
{
$extension = strtolower($extension);
$files = array();
$it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory));
while($it->valid())
{
if (!$it->isDot() && endsWith(strtolower($it->key()), $extension))
{
array_push($files, $it->key());
}
$it->next();
}
return $files;
}
function endsWith($haystack, $needle)
{
return $needle === "" || substr($haystack, -strlen($needle)) === $needle;
}
Used like so
print_r(getDirectoryContents('folder/', '.php'));
It converts the extension to lowercase to compare against
Take a look at this code:
<?php
class ex{
private function get_files_array($path,$ext, &$results){ //&to ensure it's a reference... but in php obj are passed by ref.
if (!is_dir($path)) {
//throw new AisisCore_FileHandling_FileException("Could not find said path: " . $path);
}
if ($dir = opendir($path)) {
$extLength = strlen($ext);
while (false !== ($file = readdir($dir))) {
if ($file != '.' && $file != '..'){
if (is_file($path.'/'.$file) && substr($file,-$extLength) == $ext){
$results[] = $path . '/' . $file; //it's a file and the correct extension
}
elseif (is_dir($path . '/'. $file)){
$this->get_files_array($path.'/'.$file, $ext, $results); //it's a dir
}
}
}
}else{
//unable to open dir
}
}
public function get_files_deep($path,$ext){
$results = array();
$this->get_files_array($path,$ext,$results);
return $results;
}
}
$ex = new ex();
var_dump($ex->get_files_deep('_some_path','.less'));
?>
It will retrieve all the files with the matching extension in the path and it's sub directories.
I hope it's what you need.

scandir() to sort by date modified

I'm trying to make scandir(); function go beyond its written limits, I need more than the alpha sorting it currently supports. I need to sort the scandir(); results to be sorted by modification date.
I've tried a few solutions I found here and some other solutions from different websites, but none worked for me, so I think it's reasonable for me to post here.
What I've tried so far is this:
function scan_dir($dir)
{
$files_array = scandir($dir);
$img_array = array();
$img_dsort = array();
$final_array = array();
foreach($files_array as $file)
{
if(($file != ".") && ($file != "..") && ($file != ".svn") && ($file != ".htaccess"))
{
$img_array[] = $file;
$img_dsort[] = filemtime($dir . '/' . $file);
}
}
$merge_arrays = array_combine($img_dsort, $img_array);
krsort($merge_arrays);
foreach($merge_arrays as $key => $value)
{
$final_array[] = $value;
}
return (is_array($final_array)) ? $final_array : false;
}
But, this doesn't seem to work for me, it returns 3 results only, but it should return 16 results, because there are 16 images in the folder.
function scan_dir($dir) {
$ignored = array('.', '..', '.svn', '.htaccess');
$files = array();
foreach (scandir($dir) as $file) {
if (in_array($file, $ignored)) continue;
$files[$file] = filemtime($dir . '/' . $file);
}
arsort($files);
$files = array_keys($files);
return ($files) ? $files : false;
}
This is a great question and Ryon Sherman’s answer provides a solid answer, but I needed a bit more flexibility for my needs so I created this newer function: better_scandir.
The goal is to allow having scandir sorting order flags work as expected; not just the reverse array sort method in Ryon’s answer. And also explicitly setting SORT_NUMERIC for the array sort since those time values are clearly numbers.
Usage is like this; just switch out SCANDIR_SORT_DESCENDING to SCANDIR_SORT_ASCENDING or even leave it empty for default:
better_scandir(<filepath goes here>, SCANDIR_SORT_DESCENDING);
And here is the function itself:
function better_scandir($dir, $sorting_order = SCANDIR_SORT_ASCENDING) {
/****************************************************************************/
// Roll through the scandir values.
$files = array();
foreach (scandir($dir, $sorting_order) as $file) {
if ($file[0] === '.') {
continue;
}
$files[$file] = filemtime($dir . '/' . $file);
} // foreach
/****************************************************************************/
// Sort the files array.
if ($sorting_order == SCANDIR_SORT_ASCENDING) {
asort($files, SORT_NUMERIC);
}
else {
arsort($files, SORT_NUMERIC);
}
/****************************************************************************/
// Set the final return value.
$ret = array_keys($files);
/****************************************************************************/
// Return the final value.
return ($ret) ? $ret : false;
} // better_scandir
Alternative example..
$dir = "/home/novayear/public_html/backups";
chdir($dir);
array_multisort(array_map('filemtime', ($files = glob("*.{sql,php,7z}", GLOB_BRACE))), SORT_DESC, $files);
foreach($files as $filename)
{
echo "<a>".substr($filename, 0, -4)."</a><br>";
}
Another scandir keep latest 5 files:
public function checkmaxfiles()
{
$dir = APPLICATION_PATH . '\\modules\\yourmodulename\\public\\backup\\';
// '../notes/';
$ignored = array('.', '..', '.svn', '.htaccess');
$files = array();
foreach (scandir($dir) as $file) {
if (in_array($file, $ignored)) continue;
$files[$file] = filemtime($dir . '/' . $file);
}
arsort($files);
$files = array_keys($files);
$length = count($files);
if($length < 4 ){
return;
}
for ($i = $length; $i > 4; $i--) {
echo "Erase : " .$dir.$files[$i];
unlink($dir.$files[$i]);
}
}

How get first modified file in a folder using PHP?

How get first modified file?
So far I've had:
$dir = $path.'/';
$firstMod = '';
$p = 1;
foreach (scandir($dir) as $file) {
if (is_file($dir.$file) && ... ) {
if($p == 1) break;
}
}
If I would like to get last file but not last modified but last in an folder order what should I use?
you can try to write all the files in the array make key as the date modified than reorder the array based on date and get the first element of array which would first modified.
<?php
$folder = "files/";
$handle = opendir($folder);
$files=array();
while ($file = readdir($handle)){
if( $file != ".." && $file != "." ){
$key = filemtime($file);
$files[$key] = $file ;
}
}
closedir($handle);
ksort($files) ;
echo reset($files);
?>

How to count number of files in a directory using PHP?

How to count the number of files in a directory using PHP?
Please answer for the following things:
1. Recursive Search: The directory (which is being searched) might be having several other directories and files.
2. Non-Recursive Search: All the directories should be ignored which are inside the directory that is being searched. Only files to be considered.
I am having the following code, but looking for a better solution.
<?php
$files = array();
$dir = opendir('./items/2/l');
while(($file = readdir($dir)) !== false)
{
if($file !== '.' && $file !== '..' && !is_dir($file))
{
$files[] = $file;
}
}
closedir($dir);
//sort($files);
$nooffiles = count($files);
?>
Recursive:
$it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir));
$count = 0;
while($it->next()) $count++;
Most of the mentioned ways for "Non-Recursive Search" work, though it can be shortened using PHP's glob filesystem function.
It basically finds pathnames matching a pattern and thus can be used as:
$count = 0;
foreach (glob('path\to\dir\*.*') as $file) {
$count++;
}
The asterisk before the dot denotes the filename, and the one after denotes the file extension. Thus, its use can further be extended to counting files with specific filenames, specific extensions or both.
non-recrusive:
$dir = opendir('dir/');
$i = 0;
while (false !== ($file = readdir($dir))){
if (!in_array($file, array('.', '..') and !is_dir($file)) $i++;
}
echo "There were $i files";
recrusive:
function crawl($dir){
$dir = opendir($dir);
$i = 0;
while (false !== ($file = readdir($dir)){
if (is_dir($file) and !in_array($file, array('.', '..'))){
$i += crawl($file);
}else{
$i++;
}
}
return $i;
}
$i = crawl('dir/');
echo "There were $i files";
Might be useful for you:
http://www.php.net/manual/en/class.dir.php
http://www.php.net/manual/en/function.is-file.php
But, i think, there is no other good solutions.
Rather than posting code for you, I would provide the outline of what you should do as you seem to have the basic code already.
Place your code in a function. Have two parameters ($path, $recursive = FALSE) and within your code, separate the is_dir() and if that's true and the recursive flag is true, then pass the new path (path to the current file) back to the function (self reference).
Hope this helps you learn, rather than copy paste :-)
Something like this might work:
(might need to add some checks for '/' for the $dir.$file concatenation)
$files = array();
$dir = './items/2/l';
countFiles($dir, $files); // Recursive
countFiles($dir, $files, false); // Not recursive;
var_dump(count($files));
function countFiles($directory, &$fileArray, $recursive = true){
$currDir = opendir($directory);
while(($file = readdir($dir)) !== false)
{
if(is_dir($file) && $recursive){
countFiles($directory.$fileArray, $saveArray);
}
else if($file !== '.' && $file !== '..' && !is_dir($file))
{
$fileArray[] = $file;
}
}
}
Recursive:
function count_files($path) {
// (Ensure that the path contains an ending slash)
$file_count = 0;
$dir_handle = opendir($path);
if (!$dir_handle) return -1;
while ($file = readdir($dir_handle)) {
if ($file == '.' || $file == '..') continue;
if (is_dir($path . $file)){
$file_count += count_files($path . $file . DIRECTORY_SEPARATOR);
}
else {
$file_count++; // increase file count
}
}
closedir($dir_handle);
return $file_count;
}
Non-Recursive:
$directory = ".. path/";
if (glob($directory . "*.") != false)
{
$filecount = count(glob($directory . "*."));
echo $filecount;
}
else
{
echo 0;
}
Courtesy of Russell Dias
You can use the SPL DirectoryIterator to do this in a non-recursive (or with a recursive iterator in a recursive) fashion:
iterator_count(new DirectoryIterator($directory));
It's good to note that this will not just count regular files, but also directories, dot files and symbolic links. For regular files only, you can use:
$directory = new DirectoryIterator($directory);
$count = 0;
foreach($directory as $file ){ $count += ($file->isFile()) ? 1 : 0;}
PHP 5.4.0 also offers:
iterator_count(new CallbackFilterIterator($directory, function($current) { return $current->isFile(); }));
$dir = opendir('dir/');
$i = 0;
while (false !== ($file = readdir($dir))){
if (!in_array($file, array('.', '..' ))and (!is_dir($file)))
$i++;
}
echo "There were $i files";

displaying files and DIRECTORIES via php?

i have a propably rather simple question:
I'm using the following script to read a folder?
$count = 0;
if ($handle = opendir(PATH)) {
$retval = array();
while (false !== ($file = readdir($handle))) {
$ext = pathinfo($file, PATHINFO_EXTENSION);
if ($file != '.' && $file != '..' && $file != '.DS_Store' && $file != 'Thumbs.db') {
$retval[$count] = $file;
$count = $count + 1;
} else {
//no proper file
}
}
closedir($handle);
}
if a file is an image I print it as an image: print "";
However i wonder how i can display FOLDERS? If i have a subfolder inside of the folder i'm currently running through? how can i print that one?
use glob instead of scandir
$dirs = glob(PATH."/*", GLOB_ONLYDIR);
$images = glob(PATH."/*.[jJ][pJ][gG]");
foreach ($dirs as $name) echo "<b>$name</b><br>\n";
foreach ($images as $name) echo $name."<br>\n";
Use scandir instead of readdir. http://us.php.net/manual/en/function.scandir.php

Categories