1

I have some file list arrays with elements exceeding 100s in number that I need to convert to a tree array and insert them into the database and return the tree on call for a json api directory system I have spent a week trying different algorithms, all of them fail at some point. This is the array:

$files[] = array('dir1/dir2/dir3/file1.mkv', 44444);
$files[] = array('dir1/dir2/dir3/file2.mkv', 44444);
$files[] = array('dir1/dir2/file1.mkv', 44444);
$files[] = array('dir1/dir2/file2.txt', 11111);
$files[] = array('dir1/file1.exe', 22222);
$files[] = array('dir1/file2.exe', 22222);
$files[] = array('file1.rar', 3333);

the first element is the file path, second element is filesize. These files dont exist on this server, they are on a different server, this is the api server. I need to convert it into a nested tree array like this:

Array
(
    [dir1] => Array
        (
            [dir2] => Array
                (
                    [dir3] => Array
                    (
                        [0] => Array
                            (
                                [name] => file1.mkv
                                [size] => 44444
                            )

                        [1] => Array
                            (
                                [name] => file2.mkv
                                [size] => 44444
                            )

                    )

                    [0] => Array
                        (
                            [name] => file1.mkv
                            [size] => 44444
                        )

                    [1] => Array
                        (
                            [name] => file2.txt
                            [size] => 11111
                        )

                )

            [0] => Array
                (
                    [name] => file1.exe
                    [size] => 22222
                )

            [1] => Array
                (
                    [name] => file2.exe
                    [size] => 22222
                )

        )

    [0] => Array
        (
            [name] => file1.rar
            [size] => 3333
        )

)

I wrote some code but it only goes up to 2nd level (dir2), then on the third level (dir3), it fails to perform as expected.

the code:

foreach ($files as $file)
{
    $info = pathinfo($file[0]);
    if ($info['dirname'] != '.')
    {
        if (strpos($info['dirname'], '/') !== false)
        {
            $dirs[pathinfo($info['dirname'])['dirname']][pathinfo($info['dirname'])['basename']][] = array('name' => $info['basename'], 'size' => $file[1]);
        }
        else
        {
            $dirs[$info['dirname']][] = array('name' => $info['basename'], 'size' => $file[1]);
        }
    }
    else
    {
        $dirs[] = array('name' => $info['basename'], 'size' => $file[1]);
    }
}

This code returns the array fine if I remove the dir3 level from the file list array, but with the dir3 present, it gives:

Array
(
    [dir1/dir2] => Array
        (
            [dir3] => Array
                (
                    [0] => Array
                        (
                            [name] => file1.mkv
                            [size] => 44444
                        )

                    [1] => Array
                        (
                            [name] => file2.mkv
                            [size] => 44444
                        )

                )

        )

    [dir1] => Array
        (
            [dir2] => Array
                (
                    [0] => Array
                        (
                            [name] => file1.mkv
                            [size] => 44444
                        )

                    [1] => Array
                        (
                            [name] => file2.txt
                            [size] => 11111
                        )

                )

            [0] => Array
                (
                    [name] => file1.exe
                    [size] => 22222
                )

            [1] => Array
                (
                    [name] => file2.exe
                    [size] => 22222
                )

        )

    [0] => Array
        (
            [name] => file1.rar
            [size] => 3333
        )

)

This [dir1/dir2] is the problem, I need it to be a perfect tree so I can recurs through it and insert the records into the database.

2 Answers 2

2

Since you don't know tree depth beforehand, you can't manage this with if/else loops. It is a use case that needs recursion.

<?php
function scanpath($path) {
    $myscan = scandir($path);
    $tree=[];
    foreach($myscan as $entry) {
        //echo '<br>'.$entry;
        if($entry==='.' || $entry ==='..') {
            // do nothing
        } else  if(is_dir($path.'/'.$entry)) {
            // this is a folder, I will recurse
            $tree[$entry] = scanpath($path.'/'.$entry);
        } else {
            // this is a file or link. Value is file size
            $tree[$entry] = filesize($path.'/'.$entry);
        }
    }
    return $tree;
}
$scanresult=scanpath(__DIR__);
echo '<pre>';
print_r($scanresult);
echo '</pre>';

You see, I call a function on a given path. For each entry on that path I

  • Discard . and ..
  • If it's a folder, the node will contain the result of applying that function to the subpath
  • In any other case, the node will contain the file size

You'll need to modify my code to suit your needs. I can tell your "is file or link" case has a different format.

EDIT: since there isn't a real file structure to scan, but instead you have an array of paths, this is the solution I came with

<?php
$thefiles=[];

$thefiles[] = array('dir1/dir2/dir3/file1.mkv', 44444);
$thefiles[] = array('dir1/dir2/dir3/file2.mkv', 44444);
$thefiles[] = array('dir1/dir2/file1.mkv', 44444);
$thefiles[] = array('dir1/dir2/file2.txt', 11111);
$thefiles[] = array('dir1/dir4/file5.mkv', 22444);
$thefiles[] = array('dir1/dir4/file6.txt', 15111);
$thefiles[] = array('dir1/file1.exe', 22222);
$thefiles[] = array('dir1/file2.exe', 22222);
$thefiles[] = array('file1.rar', 3333);

$filearray=[];

function scanpath($patharray,$filesize) {
    $tree=[];
    if(count($patharray)===1) {
        $filename=array_pop($patharray);
        $tree[] = ['name'=>$filename, 'size'=>$filesize];
    } else {
        $pathpart = array_pop($patharray);
        $tree[$pathpart] = scanpath($patharray,$filesize);
    }
    return $tree;
}

foreach($thefiles as $fileentry) {
    $patharray=array_reverse(explode('/',$fileentry[0]));
    $thisarray = scanpath($patharray,$fileentry[1]);
    $filearray= array_merge_recursive($filearray,$thisarray);
}

echo '<pre>';
print_r($filearray);
echo '</pre>';

I exploded each path using slash as separator, then recursed on the path, folder by folder, until I get to the final part and the recursion ends on a file name and size.

Sign up to request clarification or add additional context in comments.

5 Comments

I said the files dont exist. its just an array, so you cannot do scandir() or is_dir()
I see. Sorry about that. I'll give it a shot in a few hours.
that would be appreciated :)
It seems I got it working, please see my edited answer.
Hey, sorry for the late response. I already figured it out. But thanks for the help :)
0

Here is my way

$path='E:\conf\transfer';
$objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path), RecursiveIteratorIterator::SELF_FIRST);
$tree_array=array();
foreach($objects as $name => $object){
    if(in_array($object->getFilename(),array('..','.')) || is_dir($object->getPathname()))
    {
        continue;
    }
    $path_info=explode(DIRECTORY_SEPARATOR ,$object->getPathname());
    $file_name=array_pop($path_info);
    $path_info="['".implode("']['",$path_info)."']";
    $code='$tree_array'.$path_info.'[] = '.'\''.$file_name.'\';';
    eval($code);
}

var_dump($tree_array);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.