How to put all file names in php array - php

How do I put every file name on the root directory and and all the file names in each sub folder into an array in php?

Use scandir() and you'll find a recursive function for sub-directories as well as tons of other examples to achieve what you want.

I have always preferred DirectoryIterator and RecursiveDirectoryIterator.
Here is an example:
function drawArray(DirectoryIterator $directory)
{
$result=array();
foreach($directory as $object)
{
if($object->isDir()&&!$object->isDot())
{
$result[$object->getFilename()]=drawArray(new DirectoryIterator($object->getPathname()));
}
else if($object->isFile())
{
$result[]=$object->getFilename();
}
}
return $result;
}
$array=drawArray(new DirectoryIterator('/path'));
print_r($array);

Have a look at glob() [and give condolence to your RAM by the way if you really want to skim all your files].

This is how I do it.
/**
Recursively returns all the items in the given directory alphabetically as keys in an array, optionally in descending order.
If a key has an array value it's a directory and its items are in the array in the same manner.
*/
function scandir_tree($directory_name, $sort_order = SCANDIR_SORT_ASCENDING, $_recursed = false)
{
if (!$_recursed || is_dir($directory_name))
{
$items = array_diff(scandir($directory_name, (int) $sort_order), ['.', '..']);
$tree = [];
foreach ($items as $item)
{
$tree[$item] = scandir_tree($directory_name . $item, $sort_order, true);
}
return $tree;
}
return $directory_name;
}

Try this:
$ar=array();
$g=scandir('..');
foreach($g as $x)
{
if(is_dir($x))$ar[$x]=scandir($x);
else $ar[]=$x;
}
print_r($ar);

Related

Folders first from RecursiveDirectoryIterator

I wrote this code a long time ago to get files from a folder structure given in $dir.
$recursiveIterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir), RecursiveIteratorIterator::CHILD_FIRST);
$ritit = new RegexIterator($recursiveIterator, $filter);
foreach ($ritit as $splFileInfo) {
if(($splFileInfo->getFileName() != ".") && ($splFileInfo->getFileName() != "..")) {
$path = $splFileInfo->isDir()
? array($splFileInfo->getFilename() => array())
: array($splFileInfo->getFilename());
for ($depth = $ritit->getDepth() - 1; $depth >= 0; $depth--) {
$path = array($ritit->getSubIterator($depth)->current()->getFilename() => $path);
}
$return = array_merge_recursive($return, $path);
}
}
And as the title suggests, I want the $return array to have the folders first. I first attempted to correct this with a foreach after the loop, and sort into $folders and $files array, however this wouldnt change the contents inside the folders, if there were mutliple children inside children.
Is there a way to modify the above loop so that all folders appear first in the array and files after? Including children and children's children?
I don't think that you can modify the loop to get the output array the way you want it. Instead, I'd rather use recursive sorting function to sort the array after the loop.
First, create function that defines the logic for sorting elements. In your case, you want the array-type elements to be the first elements in a tier, so the sorting function could look like this:
function dirFirstSorting($a, $b)
{
if (is_array($a) && is_string($b)) {
return -1;
} elseif (is_string($a) && is_array($b)) {
return 1;
} else {
return 0;
}
}
Then, create a function that recursively sorts elements in array:
function sortFilesListing(&$array)
{
if (is_array($array)) {
uasort($array, "dirFirstSorting");
array_walk($array, "sortFilesListing");
}
}
All you need to do now, is to call sortFilesListing function with $return array provided:
sortFilesListing($return);
The $return array elements should be now sorted accordingly.

Alter PHP Array

I'm need an array of all the folders in a directory, im using laravel to get an array of folders in the directory using the below code.
Storage::allDirectories('/public');
this returns an array like below.
$directories = [
"Gallery",
"Images",
"Images/Proof",
"Images/Proof/Another",
];
I need a way to remove duplicate parent directories, so for example Images will be remove if Images/Proof/Another exists or something like that, i just need to build an array of a directory and its subfolders as one array, if that makes sense.
so for example:
$directories = [
["Gallery"],
["Images/Proof/Another"],
];
Or something like this, I can't think of a way to get this to work.
I'm building a custom media manager component if anyone was wondering, some exist but i have no control over them so i built my own.
all help is appreciated.
Can you post the code you have tried so far
For 1 i can't get my head around the logic, thats why im asking what i've done "Which i dont see how it would help at all"
foreach (Storage::allDirectories('/public') as $folder)
{
$all_folders[] = $exploded('/',$folder);
}
Im trying to separate the array into smaller arrays and check each exploded bit against another. But this has me running in circles.
Do like below (Easiest way):-
$final_array = [];
foreach($directories as $dir){
$final_array[explode('/',$dir)[0]] = $dir;
}
$final_array =array_values($final_array);
Output:- https://eval.in/912417
Or:-
$final_array = [];
foreach($directories as $dir){
$final_array[explode('/',$dir)[0]][0] = $dir;
}
$final_array =array_values($final_array);
Output:-https://eval.in/912418
If you rsort (descending) it and foreach it you can then use preg_grep to see if it exsists in your new array.
If not add it.
$directories = [
"Gallery",
"Images",
"Images/Proof",
"Images/Proof/Another",
];
Rsort($directories);
$new=[];
Foreach($directories as $val){
If(!preg_grep("~" . $val. ".*~",$new)){
$new[] = $val;
}
}
Var_dump($new);
https://3v4l.org/0EnZ3
Preg_grep will look for the pattern and see if it exsists in the array.
Since I loop descending it will first look at Images/Proof/Another then add it to the list because it's not there.
Next iteration will look at Images/Proof/ and since preg_grep has pattern Images/Proof/.* it will be true thus not add it in the list.
Then the same with images.
You can just filter array using array_filter function.
<?php
$directories = [
"Gallery",
"Images",
"Images/Proof",
"Images/Proof/Another",
];
$filtered = array_filter($directories, function($v) use ($directories) {
foreach($directories as $dir) {
if(strpos($dir, $v . "/") === 0) {
return false;
}
}
return true;
});
var_dump($filtered);
Not so elegant, but clear to read.
Quick and dirty, but tested and works
function removeRedundantParents($directories)
{
foreach ($directories as $key => &$val)
{
foreach ($directories as $i => &$v)
{
if ($val !== $v && substr($v, 0, strlen($val)) == $val)
{
unset($directories[$key]);
continue;
}
}
}
return $directories;
}
I achieved this by removing the row if it satisfies the logic.
Mutative, but satisfies the requirement correctly.
Tested, works properly.
check out https://eval.in/912439 for the snippet and output
Code
$directories = array_flip($directories);
foreach ($directories as $dir => $key) {
$parent_dir = preg_match('/(.*)\//', $dir, $match);
if (isset($match[1])) {
unset($directories[$match[1]]);
}
}
$directories = array_keys($directories);

PHP - Directory browsing from recursive to iterative

Hello I am trying to make the following function iterative. It browses threw all directories and gives me all files in there.
function getFilesFromDirectory($directory, &$results = array()){
$files = scandir($directory);
foreach($files as $key => $value){
$path = realpath($directory.DIRECTORY_SEPARATOR.$value);
if(!is_dir($path)) {
$results[] = $path;
} else if($value != "." && $value != "..") {
getFilesFromDirectory($path, $results);
$results[] = $path;
}
}
return $results;
}
I am sure that it is possible to make this function iterative but I really have no approach how I can do this.
Your going to want to use a few PHP base classes to implement this.
Using a RecursiveDirectoryIterator inside of a RecursiveIteratorIterator will allow you to iterate over everything within a directory regardless of how nested.
Its worth noting when looping over the $iterator below each $item is an object of type SplFileinfo. Information on this class can be found here: http://php.net/manual/en/class.splfileinfo.php
<?php
//Iterate over a directory and add the filenames of all found children
function getFilesFromDirectory($directory){
//Return an empty array if the directory could not be found
if(!is_dir($directory)){
return array();
}
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($directory)
);
$found = array();
foreach($iterator as $item){
if(method_exists($item, 'isFile') && $item->isFile()){
//Uncomment the below to exclude dot files
//if(method_exists($item, 'isDot') && $item->isDot()){
// continue;
//}
//Pathname == full file path
$found[] = $item->getPathname();
}
}
return $found;
}
An var_dump of some found files i did using this function as a test:
Hope this helps!

can i glob dirnames to an array and then usort by a file value?

Can anyone please advise whether I can write a function for usort that will do the following in PHP :
Firstly I have a bunch of directories that all have two files inside - these two files each contain a number as plain text
Here is what I want to do :
glob the list of directories into an array call $dirs
use a usort function to do the following :
Read the two files (file1.txt and file2.txt) in each directory and multiply them together to create a 3rd number called $value
Sort the original $dirs array into descending order by the $value for each dir.
Ok - I can glob the files like this:
$dirs = glob('*',GLOB_NOSORT|GLOB_ONLYDIR);
and I can pull the values easily enough using file_get_contents but I can't figure out how to combine all of this into a function for usort.
Try this:
<?php
$dirs = array();
foreach (glob('*',GLOB_NOSORT|GLOB_ONLYDIR) as $dir) {
$value =
(int)file_get_contents($dir.'/file1.txt') *
(int)file_get_contents($dir.'/file2.txt') ;
$dirs[] = array(
'path' => $dir,
'value' => $value,
);
}
usort($dirs, function($a, $b) {
return $b['value'] - $a['value'];
});
Then you want to get one-dimensional result,
$dirs = array_map(function ($dir) {
return $dir['path'];
}, $dirs);
The following snippet will do the trick:
$dirs = glob('*',GLOB_NOSORT|GLOB_ONLYDIR);
usort($dirs, function ($a, $b) {
$val_a = $val_b = 1;
foreach(scandir($a) as $file) {
if(strpos($file, '.') === 0) {
continue;
}
$val_a *= intval(trim(file_get_contents($a. '/' . $file)));
}
foreach(scandir($b) as $file) {
if(strpos($file, '.') === 0) {
continue;
}
$val_b *= intval(trim(file_get_contents($b. '/' . $file)));
}
if($val_a === $val_b) {
return 0;
} else if($val_a > $val_b) {
return 1;
} else {
return -1;
}
});
var_dump($dirs);
Assuming you're using 5.3.0 or better, you can use an anonymous function to do this. Below you will see the function buildSort, which returns a function object (called by PHP a "closure", although it's heavily debated in some circles whether this term is being correctly applied.) We'll use this to "memoize" the reads of dir/file1.txt and dir/file2.txt, as well as the math operations, so we only need to perform those once per directory:
<?php
function buildSort(&$values) {
return function ($a, $b) use(&$values) {
if (!isset($values[$a])) {
$values[$a] = file_get_contents($a.'/file1.txt')*
file_get_contents($a.'/file2.txt');
}
if (!isset($values[$b])) {
$values[$b] = file_get_contents($b.'/file1.txt')*
file_get_contents($b.'/file2.txt');
}
return strcmp($values[$a], $values[$b]);
};
}
$dirs = glob('*',GLOB_NOSORT|GLOB_ONLYDIR);
$values = array();
$sort = buildSort($values);
usort($dirs, $sort);
var_dump($dirs);
The answer that avoids passing $values by reference is left as an exercise for the reader. :)

Multidimensional Arrays Nested to Unlimited Depth

I have a multidimensional array nested to an unknown/unlimited depth.
I'd like to be able to loop through every element.
I don't want to use, foreach(){foreach(){foreach(){}}} as I don't know the depth.
I'm eventually looking for all nested arrays called "xyz". Has anyone got any suggestions?
I'm eventually looking for all nested arrays called "xyz". Has anyone got any suggestions?
Sure. Building on the suggestions to use some iterators, you can do:
$iterator = new RecursiveIteratorIterator(
new RecursiveArrayIterator($array),
RecursiveIteratorIterator::SELF_FIRST
);
foreach ($iterator as $key => $item) {
if (is_array($item) && $key === 'xyz') {
echo "Found xyz: ";
var_dump($item);
}
}
The important difference between the other answers and this being that the RecursiveIteratorIterator::SELF_FIRST flag is being employed to make the non-leaf (i.e. parent) items (i.e. arrays) visible when iterating.
You could also make use of a ParentIterator around the array iterator, rather than checking for arrays within the loop, to make the latter a little tidier.
Recursion.
Write a function that walks one array; for each element that is also an array, it calls itself; otherwise, when it finds the target string, it returns.
There is a vast difference between unknown and unlimited. However, you can make use of the SPL Iterators instead of using multiple nested foreach loops.
Example:
$array_obj = new RecursiveIteratorIterator(new RecursiveArrayIterator($array));
foreach($array_obj as $key => $value) {
echo $value;
}
Take a look to the RecursiveIteratorIterator interface.
$interface = new RecursiveIteratorIterator( new RecursiveArrayIterator($your_array) );
foreach($interface as $k=>$v) { /* your function*/ }
Using the comments above, I've found the answer:
function findXyz($array){
foreach($array as $foo=>$bar){
if (is_array($bar)){
if ($bar["xyz"]){
echo "<br />The array of xyz has now been found";
print_r($bar['xyz']);
}else{
findXyz($bar);
}
}
}
}
findXyz($myarray);
This loops through all nested arrays and looks for any element who has a sub-array of xyz, as per my original request. array_walk_array and RecursiveIteratorIterator were unable to achieve this.
Have you thought about using array_walk_recursive for this?
Another (slower) approach would be to flatten the array first before performing a search, ie:
$myarray = array('a','b',array(array(array('x'),'y','z')),array(array('p')));
function array_flatten($array,$return)
{
for($x = 0; $x <= count($array); $x++)
{
if(is_array($array[$x]))
{
$return = array_flatten($array[$x],$return);
}
else
{
if($array[$x])
{
$return[] = $array[$x];
}
}
}
return $return;
}
$res = array_flatten($myarray,array());
Or, for a recursive search, see here for an example:
function arrayRecursiveSearch($needle, $haystack, $path=""){
if(!is_array($haystack)){
die("second argument is not array");
}
global $matches;
foreach($haystack as $key=>$value)
{
if(preg_match("/$needle/i", $key)){
$matches[] = array($path . "$key/", "KEY: $key");
}
if(is_array($value)){
$path .= "$key/";
arrayRecursiveSearch($needle, $value, $path);
unset($path);
}else{
if(preg_match("/$needle/i", $value)){
$matches[] = array($path . "$key/", "VALUE: $value");
}
}
}
return $matches;
}
$arr = array("Asia"=>array('rambutan','duku'),
"Australia"=>array('pear','kiwi'),
"Arab"=>array('kurma'));
print_r(arrayRecursiveSearch("ra",$arr));

Categories