Alter PHP Array - php

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);

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.

List of files and Folder

actully i get the folder and files from perticular path but its doesnt returns the value what i want.
im expecting the return value like:-
[{"filename":"19_0_0_0_0_1.jpg","RFI":19},
{"filename":"19_0_0_0_0_2.jpg","RFI":19},
{"filename":"19_20005_1_0_0_1.jpg","RFI":19},
{"filename":"19_20005_1_0_0_2.jpg","RFI":19},
{"filename":"19_20005_1_429_0_1.jpg","RFI":19},
{"filename":"19_20005_1_429_0_2.jpg","RFI":19},
{"filename":"19_20005_1_429_1_1.jpg","RFI":19},
{"filename":"19_20005_1_429_1_2.jpg","RFI":19},
{"filename":"19_20027_1_0_0_1.jpg","RFI":19}]
and its give me like this output :
[{"filename":[{"filename":"19_0_0_0_0_1.jpg","RFI":19},
{"filename":"19_0_0_0_0_2.jpg","RFI":19},
{"filename":"19_20005_1_0_0_1.jpg","RFI":19},
{"filename":"19_20005_1_0_0_2.jpg","RFI":19},
{"filename":"19_20005_1_429_0_1.jpg","RFI":19},
{"filename":"19_20005_1_429_0_2.jpg","RFI":19},
{"filename":"19_20005_1_429_1_1.jpg","RFI":19},
{"filename":"19_20005_1_429_1_2.jpg","RFI":19},
{"filename":"19_20027_1_0_0_1.jpg","RFI":19}],"RFI":19}]
this is my code:
$ldir = "D:\php\EIL_App\RFIImages";
$data = listFolderFiles($ldir,19);
print json_encode($data);
function listFolderFiles($dir,$pRFI)
{
$result = array();
foreach (new DirectoryIterator($dir) as $fileInfo){
if (!$fileInfo->isDot()){
$dataimg = $fileInfo->getFilename();
if($fileInfo->getFilename() == $pRFI){
if ($fileInfo->isDir()){
$dataimg = listFolderFiles($fileInfo->getPathname(),$pRFI);
}
array_push($result,array('filename'=>$dataimg,'RFI'=>$pRFI));
}
}
}
return $result;
}
Please give the suggestion what can i do???
Thanks in advance.
There's no need to complicate things
$prefix = 19;
$dir = "D:\php\EIL_App\RFIImages";
$data = glob("$prefix*.*",19); // it will give you array with all files matching pattern
// then you can do a loop
$arr = [];
foreach ($data as $filename) {
$arr[] = ['filename' => $filename, 'prefix' => $prefix];
}
echo json_encode($arr);
http://php.net/manual/en/function.glob.php
If you want to use iterator then use glob http://php.net/manual/en/globiterator.construct.php
Regarding your code
if ($fileInfo->isDir()) this makes no sense because it will never go to this if. It's because before you check if (!$fileInfo->isDot()){ and dot means either . or .. which applies to directories. If you want to do it recursively then you can use
Edit:
I've noticed you do some recursion if so then probably it'd be better to use ResursiveIterator
function listFolderFiles($dir, $prefix) {
$rii = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir));
$files = new RegexIterator($rii, "^$prefix.*", RegexIterator::GET_MATCH); // note prefix cannot have characters that are special to regex or they should be escaped
$arr = array();
foreach($files as $file) {
$arr[] = $file;
}
return $arr;
}
http://php.net/manual/en/class.recursivedirectoryiterator.php
http://php.net/manual/en/directoryiterator.isdot.php

how to get all keys that lead to given value when iterating multilevel array in php

Example:
$arr = array(array("name"=>"Bob","species"=>"human","children"=>array(array("name"=>"Alice","age"=>10),array("name"=>"Jane","age"=>13)),array("name"=>"Sparky","species"=>"dog")));
print_r($arr);
array_walk_recursive($arr, function($v,$k) {
echo "key: $k\n";
});
The thing here is that I get only the last key, but I have no way to refer where I been, that is to store a particular key and change value after I left the function or change identical placed value in another identical array.
What I would have to get instead of string is an array that would have all keys leading to given value, for example [0,"children",1,"age"].
Edit:
This array is only example. I've asked if there is universal way to iterate nested array in PHP and get full location path not only last key. And I know that there is a way of doing this by creating nested loops reflecting structure of the array. But I repeat: I don't know the array structure in advance.
To solve your problem you will need recursion. The following code will do what you want, it will also find multiple paths if they exists:
$arr = array(
array(
"name"=>"Bob",
"species"=>"human",
"children"=>array(
array(
"name"=>"Alice",
"age"=>10
),
array(
"name"=>"Jane",
"age"=>13
)
),
array(
"name"=>"Sparky",
"species"=>"dog"
)
)
);
function getPaths($array, $search, &$paths, $currentPath = array()) {
foreach ($array as $key => $value) {
if (is_array($value)) {
$currentPath[] = $key;
if (true !== getPaths($value, $search, $paths, $currentPath)) {
array_pop($currentPath);
}
} else {
if ($search == $value) {
$currentPath[] = $key;
$paths[] = $currentPath;
return true;
}
}
}
}
$paths = array();
getPaths($arr, 13, $paths);
print_r($paths);

How to put all file names in php array

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);

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