With a URI such as /test/test/test, I would like a way to create an array from $__SERVER['request_uri'] such as this:
[0] => '/' [1] => /test/ [2] => /test/test/ [3] => /test/test/test/
Any help would be appreciated!
A quick an dirty script I just created for you:
<?
$path = "/test/test2/test3";
$arr = explode("/", $path);
$arraynew = array();
$i=0;
foreach ($arr as $k => $v) {
if (($k==0) && ($v=="")) {
$arraynew[$i] = "/";
$i++;
continue;
}
if ($i == 1) {
$arraynew[$i] = $arraynew[$i-1] . $v;
} else {
$arraynew[$i] = $arraynew[$i-1] . "/" . $v;
}
$i++;
}
print_r($arraynew);
?>
Or this one that's more clean and simple and adds "/" at the end:
<?
$path = "/test/test2/test3";
$arr = explode("/", $path);
$arraynew = array();
$i=0;
foreach ($arr as $k => $v) {
$i > 0 ? $arraynew[] = $arraynew[$i-1] . $v . "/" : $arraynew[] = "/";
$i++;
}
print_r($arraynew);
?>
Look up the dirname() function.
It gives you the parent directory of any given filename or directory name.
In your case, simply use it repeatedly (in a loop) to get each successive parent folder name.
Related
I have dynamic multidimensional array that contain directory, sub-directory and file names in a project folder, key indicating a sub-directory name and value indicating file names, if a key equal to number indicating only file and then if a key hasn't any value indicating there is no file at all in a directory. The array look like this :
Array
(
[0] => index.php
[src] => Array
(
[src2] => Array
(
[src3] => Array
(
[0] => test_src3.php
)
[0] => Array
(
[0] => test_src2.php
)
)
[0] => test_src.php
)
[src_test] => Array
(
[New Folder] => Array
(
)
[src_test2] => Array
(
[New Folder] => Array
(
)
[src_test3] => Array
(
)
)
)
[1] => test.php
)
The number of dimensions might be change based on sub directories that found in a folder path inputted by user (this program is used by a person in their local).
How could i fetch those array elements so that the result would be like this :
array(
[0] => src/src2/src3/
[1] => src_test/New Folder/
[2] => src_test/src_test2/New Folder/
[3] => src_test/src_test2/src_test3/
)
By the way i have a function to achieve this :
<?php
// Get specific element where the first index is 1 instead of 0
function getAtPos($tmpArray,$pos) {
$keys = array_keys($tmpArray);
return array($keys[$pos-1] => $tmpArray[$keys[$pos-1]]);
}
// Get all Keys that has String type only
function getKeyStr(array $mixed, $numbIdx){
$results = [];
$tmp = array_keys($mixed);
$ii = 0;
for ($i=1; $i <= $numbIdx; $i++) {
$keyArr = getAtPos($tmp, $i);
if (is_string($keyArr[$ii])) {
$results[] = $keyArr[$ii];
}
$ii++;
}
return $results;
}
function getKeyPaths(array $tree, $glue = '/', $return_array = true){
$paths = "";
$result = [];
foreach ($tree as $key => &$mixed) {
if (is_array($mixed) && !is_int($key)) {
$path = $key . $glue;
$retArrFalse = false;
$jlhMixed = count($mixed);
$getKeyStr = getKeyStr($mixed, $jlhMixed);
$jlhKeyStr = count($getKeyStr);
if ($jlhKeyStr < 2) {
$repeat = getKeyPaths($mixed, $glue, $retArrFalse);
$paths .= $path . $repeat;
if ($return_array) {
$paths .= "|";
}
}elseif($jlhKeyStr > 1) {
for ($i=0; $i < $jlhKeyStr; $i++) {
$idxAsso = $getKeyStr[$i];
$jlhKeySub = count($mixed[$idxAsso]);
$path2 = $idxAsso . $glue;
if ($jlhKeySub > 0) {
$paths .= $path . $path2 . getKeyPaths($mixed[$idxAsso], $glue, $retArrFalse);
if ($return_array) {
$paths .= "|";
}
}else{
$paths .= $path . $path2;
if ($return_array) {
$paths .= "|";
}
} // END of if else
} // END of for loop
} // END of elseif
}
} // END of foreach
if ($return_array) {
return explode("|", trim($paths, "|"));
}
return $paths;
}
the above function does not result like what i expected:
Array
(
[0] => src/src2/src3/
[1] => src_test/New Folder/
[2] => src_test/src_test2/New Folder/src_test3/
)
How do i achieve this ?
Any help would be appreciated !
UPDATE
I have modified my function trying to solve this:
<?php
// To get spesific element on dynamic associative array
function getAtPos($tmpArray,$pos) { // $pos is an index order starting with 1 instead of 0
$keys = array_keys($tmpArray);
return array($keys[$pos-1] => $tmpArray[$keys[$pos-1]]);
}
// Get key string type (associative) only in the given array
function getKeyStr(array $mixed, $numbIdx){
$results = [];
$tmp = array_keys($mixed); // change key to element (as array number).
$ii = 0;
for ($i=1; $i <= $numbIdx; $i++) {
$keyArr = getAtPos($tmp, $i);
if (is_string($keyArr[$ii])) {
$results[] = $keyArr[$ii];
}
$ii++;
}
return $results; // Return all second dimension sub-keys of the given array (parent)
}
// EDITED !
function getKeyPaths2(array $tree, $glue = '/', $return_array = true, $goToIfElse = false, $saveSameParent = []){
$paths = "";
$result = [];
$iFor = 0;
foreach ($tree as $key => &$mixed) {
if (is_array($mixed) && !is_int($key)) {
$path = $key . $glue;
$retArrFalse = false;
$jlhMixed = count($mixed);
$getKeyStr = getKeyStr($mixed, $jlhMixed); // Contain sub-keys of the second dimension of the parent
$jlhKeyStr = count($getKeyStr); // Count number of sub-keys of second dimension of parent
if ($goToIfElse !== false) {
$jlhKeyStr = $goToIfElse;
$iFor++;
unset($mixed);
$mixed = $tree;
$jlhMixed = count($mixed);
$getKeyStr = getKeyStr($mixed, $jlhMixed); // Contain sub-keys of the second dimension of the
$jlhKeyStr = count($getKeyStr); // Count number of sub-keys of second dimension of parent
}
if ($jlhKeyStr < 2) {
$repeat = getKeyPaths2($mixed, $glue, $retArrFalse);
$paths .= $path . $repeat;
if (!$return_array && $jlhKeyStr < 1) {
$paths .= "|";
}
}elseif($jlhKeyStr > 1) {
for ($i=$iFor; $i < $jlhKeyStr; $i++) {
$idxAsso = $getKeyStr[$i];
$jlhKeySub = count($mixed[$idxAsso]);
$path2 = $idxAsso . $glue;
if ($jlhKeySub > 0) {
$paths .= $path . $path2;
// TEST
$pecah = explode("|", $paths);
$saveSameParent[0] = end($pecah);
if ($return_array) {
$paths .= "|";
}
$paths .= $path . $path2 . getKeyPaths2($mixed[$idxAsso], $glue, $retArrFalse, $jlhKeyStr, $saveSameParent);
if ($return_array) {
$paths .= "|";
}
}else{
if ($goToIfElse !== false) {
$paths .= $path;
$paths .= "|";
$paths .= $saveSameParent[0] . $path2;
$paths .= "|";
}else{
$paths .= $path . $path2;
}
if ($return_array || $goToIfElse !== false) {
$paths .= "|";
}
} // END of if else
} // END of for loop
} // END of elseif
}
} // END of foreach
if ($return_array) {
return explode("|", trim($paths, "|"));
}
return $paths;
}
But this only works with my example array that i showed above.
If the given array like this, this would not work:
<?php
$tree = [];
$tree[0] = "index.php";
$tree["src"]["src2"]["src3"][0] = "test_src3.php";
$tree["src"]["src2"][0][0] = "test_src2.php";
$tree["src"][0] = "test_src.php";
$tree["src_test"]["New Folder"] = array();
$tree["src_test"]["src_test2"]["New Folder"] = array();
$tree["src_test"]["src_test2"]["src_test3.1"] = array();
$tree["src_test"]["src_test2"]["src_test3.2"] = array();
$tree["src_test"]["src_test2"]["src_test3.1"]["src_test3.1.1"] = array();
$tree["src_test"]["src_test2"]["src_test3.2"]["src_test3.2.1"]["src_test3.2.2"]["src_test3.2.3"] = array("test_src4.php", "test_src5.php");
The result would be :
Array
(
[0] => src/src2/src3/
[1] => src_test/New Folder/
[2] => src_test/src_test2/
[3] => src_test/src_test2/New Folder/src_test3.1/New Folder/src_test3.1/src_test3.1.1/src_test3.1.1/
[4] => New Folder/src_test3.2/New Folder/src_test3.2/src_test3.2.1/src_test3.2.1/src_test3.2.2/src_test3.2.3/
[5] => src_test3.1/src_test3.2/src_test3.1/src_test3.2/src_test3.2.1/src_test3.2.1/src_test3.2.2/src_test3.2.3/
)
I have the for loop:
I have an $request->photos array. Keys from this array are:
[1,3,5,8]
In the end, I need to get an array, where indexes are from 1 to 8 and items are boolean variables. Aside from this, I need to save the photos from the array.
Then I need to loop through the array and check if $i equals to $key:
foreach($request->photos as $key => $photo) {
for($i = 1; $i < 9; $i++) {
if ($key == $i) {
dump($key);
$path = storage_path('app/public/images/' . $pdf->id . '-' . $key . '.png');
$image = Image::make($photo->getRealPath())->widen(300)->save($path);
$imagesArray[$i] = true;
break;
} else {
$imagesArray[$i] = false;
}
}
}
And if $key equals to $i, I need to exit from loop. But in this case, break doesn't work and for loop goes on even if $key was found.
Why it goes like that?
The for loop is unnecessary. Just use the keys of $request->photos as the keys to fill in $imagesArray.
$imagesArray = array_fill(1, 8, false);
foreach ($request->photos as $key => $photo) {
dump($key);
$path = storage_path('app/public/images/' . $pdf->id . '-' . $key . '.png');
$image = Image::make($photo->getRealPath())->widen(300)->save($path);
$imagesArray[$key] = true;
}
I have to do a php script who browse a directory with sub-directory.
For each subdirectory (and maybe sub-subdirectory), I have to get filename and his parents directories.
Do you have a simple solution to do this please?
Thanks
Since I've had to create the same functionality for a website of mine too, I'll post my function as reference.
function recursiveFileSearch($path, $searchmask = "*") {
$path = rtrim($path, '/');
$files = array();
if(is_array($searchmask)) {
for($i = 0; $i < count($searchmask); $i++) {
$files = array_merge($files, glob($path.'/'.$searchmask[$i]));
}
sort($files);
} else {
$files = glob($path.'/'.$searchmask);
}
$dirs = glob($path.'/*', GLOB_ONLYDIR);
foreach($dirs as $dir) {
if(is_dir($dir)) {
$files = array_merge($files, recursiveFileSearch($dir, $searchmask));
}
}
sort($files);
return $files;
}
I am not 100% sure what you are asking, but if you take a look at the scandir documentation the first comment has a very useful recursive scanning function.
<?php
function dirToArray($dir) {
$result = array();
$cdir = scandir($dir);
foreach ($cdir as $key => $value)
{
if (!in_array($value,array(".","..")))
{
if (is_dir($dir . DIRECTORY_SEPARATOR . $value))
{
$result[$value] = dirToArray($dir . DIRECTORY_SEPARATOR . $value);
}
else
{
$result[] = $value;
}
}
}
return $result;
}
?>
The results will have the following format.
Array
(
[subdir1] => Array
(
[0] => file1.txt
[subsubdir] => Array
(
[0] => file2.txt
[1] => file3.txt
)
)
[subdir2] => Array
(
[0] => file4.txt
}
)
I currently have coded a way to turn a multidimensional array to comma separated values (I'm using pipes instead of commas for ease of debugging). The problem is, I know that the code I use to do this is bloody awful. It works how I want it to, but it's not nice at all.
What I need
Currently the arr_to_csv() function works for five levels of nested data within the multidimensional array. I need a recursive function to perform the same for one or an unlimited number of nested arrays, or a good nudge in the right direction. Recursion is not my strong point at all, but I know it's the way forward.
Data input
A multi-dimensional array is passed to the function.
array
'name' =>
array
'singular' => null
'plural' => null
'fields' =>
array
'price' =>
array
'label' => string 'Preis' (length=5)
'company_id' =>
array
'label' => null
'placeholder' => null
//...the array could go on...
The function returns the following...
This is exactly what I want...
0 => string 'name||singular||null' (length=20)
1 => string 'name||plural||null' (length=18)
2 => string 'fields||price||label||Preis' (length=27)
3 => string 'fields||company_id||label||null' (length=31)
4 => string 'fields||company_id||placeholder||null' (length=37)
5 => string 'fields||name||label||null' (length=25)
6 => string 'fields||name||placeholder||null' (length=31)
My horrible constructed function
I'm no good with recursion, so here's my awful list of foreachs. As you can see from the below code, this is terrible (no need to read the whole thing, it just copies itself). Please help me sort out my horrible code!
function arr_to_csv($data,$csv = '||') {
$array = array();
/* Epic amount of for each's. This could be done with recursion */
foreach($data as $key => &$value) {
if (!is_array($value)) {
$array[] = $key . $csv .(is_null($value)?'null':$value);
} else {
foreach ($value as $k => &$v) {
if (!is_array($v)) {
$array[] = $key . $csv . $k . $csv . (is_null($v) ? 'null' : $v);
} else {
foreach ($v as $kk => &$vv) {
if (!is_array($vv)) {
$array[] = $key . $csv . $k . $csv . $kk . $csv . (is_null($vv) ? 'null' : $vv);
} else {
foreach ($vv as $x => &$y) {
if (!is_array($y)) {
$array[] = $key . $csv . $k . $csv . $kk . $csv. $x . $csv . (is_null($y) ? 'null' : $y);
} else {
foreach ($y as $too => $long) {
if(!is_array($long)) {
$array[] = $key . $csv . $k . $csv . $kk . $csv. $x . $csv . $too . $csv. (is_null($long)?'null':$long);
} else {
foreach ($long as $omg => $why) {
if(!is_array($why)) {
$array[] = $key . $csv . $k . $csv . $kk . $csv. $x . $csv . $too . $csv . $omg . $csv . (is_null($why) ? 'null' : $why);
}
}
}
}
}
}
}
}
}
}
}
}
return $array;
}
This is some pseudocode, but it is a start:
$strings = [];
$flattenArray = function($arr, $level) use (&$strings, &$flattenArray) {
foreach($arr as $key=>$value){
$s = &$strings[$level];
if(!isset($s)) { $s = array(); }
$s[] = $key;
if(is_array($value)) {
$flattenArray($value, $level);
}
else {
$s[] = $value;
}
$level ++;
}
};
$flattenArray($myArray, 0);
foreach($strings as &$arr) {
$arr = implode("||", $arr);
}
Small demo with your array: http://codepad.viper-7.com/CR2SPY <-- It does not work fully, but it is a start
Update:
Here is a demo that I think works the way you want: http://codepad.viper-7.com/shN4pH
Code:
$strings = [];
$flattenArray = function($arr, $level, $k = null) use (&$strings, &$flattenArray) {
foreach($arr as $key=>$value){
if($k === null) {
$s = &$strings[$key];
}
else {
$s = &$strings[$k];
}
if(!isset($s)) {
$s = array();
}
$str = &$s[$level];
if(!isset($str)) {
$str = array();
if($k !== null) { $str[] = $k; }
}
$str[] = $key;
if(is_array($value)) {
$flattenArray($value, $level, ($k === null) ? $key : $k);
}
else {
$str[] = is_null($value) ? "null" : $value;
}
$level ++;
}
};
$flattenArray($myArray, 0);
$all = [];
foreach($strings as $k => $arr){
$new = array();
foreach($arr as $ky => $ar) {
$all[] = implode("||", $ar);
}
}
print_r($all);
I didn't check it, so in case it doesn't work it should be corrected.
function readarray($from_array, $addr = array()) {
global $output;
foreach ($from_array as $key => $value) {
if (is_Array($value) && count($value) > 0) {
$addr[] = $key;
readarray($value, $addr);
} else {
$output[] = implode('||', $addr) . $value;
}
}
}
$output = array();
foreach ($my_array as $key=>$value){
readarray($value);
}
// improved to get separate arrays of the root of initial array
Not sure if this will help you, but would it not be easier to flatten the array first and then format in in the way you want? To flatten the array try this:
$array = "YOUR ARRAY";
$FlatArray = array();
foreach(new RecursiveIteratorIterator(new RecursiveArrayIterator($array)) as $k=>$v)
{
$FlatArray[$k] = $v;
}
Been trying all morning to come up with a recursive function for this. This is as close as I got, Maybe you can improve upon this.
$data = array('name' =>array('singular' => NULL,'plural' => NULL,'fields' =>array('price' =>array('label' =>'Preis','company_id' =>array('label' => NULL,'placeholder' => NULL)))));
function arr_to_csv($data,$csv = '||')
{
$list = "";
foreach($data as $key => &$value)
{
$list .= $key . $csv .((!is_array($value))?(is_null($value)?'null':$value): arr_to_csv($value))."<br>";
}
return $list;
}
print_r(arr_to_csv($data));
Returns This:
name||singular||null
plural||null
fields||price||label||Preis
company_id||label||null
placeholder||null
My intent is to take a series of strings, explode them by "_" and use the keys from that array to build a "master" array.
My rules are:
if key no exists -> create key under parent array
if key exists -> add key as new array to parent
if key is last -> add value
String Examples
total_players_count
total_rosters_count
players_season1_count
players_season2_count
rosters_season1_count
Expected Results
$main = array(
'total' => array(
'players' => array(
'count' => '123',
'rosters' => array(
'count' => '123')
)
),
'players' => array(
'season1' => array(
'count' => '123'
)
)
);
I hope this shows what I've expected to write. Now let me lead into how I disappointed myself through a series of failures last night ;)
The gist is, my recursive functions haven't been working so well so I'm not posting any of that code. I've been working with array_key_exists and that isn't getting me my expected results. I came close using prev(), current(), and end() but the issue stems from an unexpected number of keys I have to parse through (otherwise I would just loop 3 times and be done. I know the following would work if I had a limited amount of keys to parse; but I don't.
<?php
private function _get_section($parent_key, $sql) {
$data = array();
$data[$parent_key] = array();
foreach ($sql AS $key => $value) {
$keys = explode('_', $key);
if ($keys[0] == $parent_key) {
$i = 0;
$total_keys = count($keys);
for ($k = 1; $k < $total_keys; $k++) {
$i++;
if ($i == 1) {
echo '1. (' . $i . ') ' . $keys[$k];
$data[$parent_key][$keys[$k]] = array();
}
else if ($i > 1 && $i < $total_keys - 1) {
$data[$parent_key][$keys[$k - 1]][$keys[$k]] = array();
}
else if ($i == $total_keys - 1) {
$tmp = array_reverse($data);
// can't get the last key because I need to recursively loop
// through the results to find where to set this last
// key / value
}
}
$k = 0;
$i = 0;
}
$keys = array();
$total_keys = 0;
}
}
Solution (thank you)
$tree = array();
foreach ($sql AS $key => $value) {
$parts = explode('_', $key);
$val = $value;
foreach (array_reverse($parts) AS $part) {
$val = array($part => $val);
}
$tree = array_merge_recursive($tree, $val);
}
untested. hopefully i didnt need to read your code to fully understand what you want, because i didnt. i just looked at the expected results + the input, although i wonder what happened to rosters_season1_count?
$tree = array();
foreach ($strings as $string) {
$parts = explode('_', $string);
$path = '123';
foreach (array_reverse($parts) as $part) {
$path = array($part => $path);
}
$tree = array_merge_recursive($tree, $path);
}