如何将简单的文件路径数组转换为表示 PHP 中文件层次结构的嵌套数组?

How to transform a simple array of file paths into a nested array representing a file hierarchy in PHP?

我需要在 PHP 中编写一个接受以下输入数组的函数:

$inputArray = [
[
    "path" => "/C",
    "basename" => "C",
    "size" => 4096,
    "modified" => 1540579748,
    "type" => "dir",
    "contents" => []
],
[
    "path" => "/C/Recycle.Bin",
    "basename" => "Recycle.Bin",
    "size" => 0,
    "modified" => 1539012172,
    "type" => "dir",
    "contents" => []
],
[
    "path" => "/C/Pictures",
    "basename" => "Pictures",
    "size" => 3164422144,
    "modified" => 1540581569,
    "type" => "file",
    "contents" => []
],
[
    "path" => "/C/Videos",
    "basename" => "Videos",
    "size" => 970752,
    "modified" => 1540579792,
    "type" => "file",
    "contents" => []
],
[
    "path" => "/C/Documents and Settings",
    "basename" => "Documents and Settings",
    "size" => 4096,
    "modified" => 1539022708,
    "type" => "link",
    "contents" => []
],
[
    "path" => "/C/Documents and Settings/Public",
    "basename" => "Public",
    "size" => 4096,
    "modified" => 1539012079,
    "type" => "dir",
    "contents" => []
],
[
    "path" => "/C/Documents and Settings/desktop.ini",
    "basename" => "desktop.ini",
    "size" => 174,
    "modified" => 1506692592,
    "type" => "file",
    "contents" => []
],
[
    "path" => "/C/PerfLogs",
    "basename" => "PerfLogs",
    "size" => 0,
    "modified" => 1506692704,
    "type" => "dir",
    "contents" => []
],
[
    "path" => "/C/Program Files",
    "basename" => "Program Files",
    "size" => 4096,
    "modified" => 1540579745,
    "type" => "dir",
    "contents" => []
],
[
    "path" => "/C/Program Files (x86)",
    "basename" => "Program Files (x86)",
    "size" => 4096,
    "modified" => 1506692707,
    "type" => "dir",
    "contents" => []
],
[
    "path" => "/C/ProgramData",
    "basename" => "ProgramData",
    "size" => 4096,
    "modified" => 1539012665,
    "type" => "dir",
    "contents" => []
],
[
    "path" => "/C/Recovery",
    "basename" => "Recovery",
    "size" => 0,
    "modified" => 1539022717,
    "type" => "dir",
    "contents" => []
],
[
    "path" => "/C/System Volume Information",
    "basename" => "System Volume Information",
    "size" => 4096,
    "modified" => 1539012967,
    "type" => "dir",
    "contents" => []
],
[
    "path" => "/C/Users",
    "basename" => "Users",
    "size" => 4096,
    "modified" => 1539012384,
    "type" => "dir",
    "contents" => []
],
[
    "path" => "/C/Windows",
    "basename" => "Windows",
    "size" => 24576,
    "modified" => 1539011957,
    "type" => "dir",
    "contents" => []
],
[
    "path" => "/C/pagefile.sys",
    "basename" => "pagefile.sys",
    "size" => 1207959552,
    "modified" => 1540581479,
    "type" => "file",
    "contents" => []
],
[
    "path" => "/C/swapfile.sys",
    "basename" => "swapfile.sys",
    "size" => 268435456,
    "modified" => 1540581479,
    "type" => "file",
    "contents" => []
]
];

并生成以下输出数组:

$outputArray = [
[
    "path" => "/C",
    "basename" => "C",
    "size" => 4096,
    "modified" => 1540579748,
    "type" => "dir",
    "contents" => [
        [
            "path" => "/C/Recycle.Bin",
            "basename" => "Recycle.Bin",
            "size" => 0,
            "modified" => 1539012172,
            "type" => "dir",
            "contents" => []
        ],
        [
            "path" => "/C/Pictures",
            "basename" => "Pictures",
            "size" => 3164422144,
            "modified" => 1540581569,
            "type" => "file",
            "contents" => []
        ],
        [
            "path" => "/C/Videos",
            "basename" => "Videos",
            "size" => 970752,
            "modified" => 1540579792,
            "type" => "file",
            "contents" => []
        ],
        [
            "path" => "/C/Documents and Settings",
            "basename" => "Documents and Settings",
            "size" => 4096,
            "modified" => 1539022708,
            "type" => "link",
            "contents" => [
                [
                    "path" => "/C/Documents and Settings/Public",
                    "basename" => "Public",
                    "size" => 4096,
                    "modified" => 1539012079,
                    "type" => "dir",
                    "contents" => []
                ],
                [
                    "path" => "/C/Documents and Settings/desktop.ini",
                    "basename" => "desktop.ini",
                    "size" => 174,
                    "modified" => 1506692592,
                    "type" => "file",
                    "contents" => []
                ]
            ]
        ],
        [
            "path" => "/C/PerfLogs",
            "basename" => "PerfLogs",
            "size" => 0,
            "modified" => 1506692704,
            "type" => "dir",
            "contents" => []
        ],
        [
            "path" => "/C/Program Files",
            "basename" => "Program Files",
            "size" => 4096,
            "modified" => 1540579745,
            "type" => "dir",
            "contents" => []
        ],
        [
            "path" => "/C/Program Files (x86)",
            "basename" => "Program Files (x86)",
            "size" => 4096,
            "modified" => 1506692707,
            "type" => "dir",
            "contents" => []
        ],
        [
            "path" => "/C/ProgramData",
            "basename" => "ProgramData",
            "size" => 4096,
            "modified" => 1539012665,
            "type" => "dir",
            "contents" => []
        ],
        [
            "path" => "/C/Recovery",
            "basename" => "Recovery",
            "size" => 0,
            "modified" => 1539022717,
            "type" => "dir",
            "contents" => []
        ],
        [
            "path" => "/C/System Volume Information",
            "basename" => "System Volume Information",
            "size" => 4096,
            "modified" => 1539012967,
            "type" => "dir",
            "contents" => []
        ],
        [
            "path" => "/C/Users",
            "basename" => "Users",
            "size" => 4096,
            "modified" => 1539012384,
            "type" => "dir",
            "contents" => []
        ],
        [
            "path" => "/C/Windows",
            "basename" => "Windows",
            "size" => 24576,
            "modified" => 1539011957,
            "type" => "dir",
            "contents" => []
        ],
        [
            "path" => "/C/pagefile.sys",
            "basename" => "pagefile.sys",
            "size" => 1207959552,
            "modified" => 1540581479,
            "type" => "file",
            "contents" => []
        ],
        [
            "path" => "/C/swapfile.sys",
            "basename" => "swapfile.sys",
            "size" => 268435456,
            "modified" => 1540581479,
            "type" => "file",
            "contents" => []
        ]
    ]
]
];

我知道这可以通过递归来完成,但我很难做到。如果有人能为我指出正确的方向或提供可行的解决方案,那就太好了。

如果数组尚未排序,则按 path 排序:

usort($inputArray, function ($a, $b) {
    return $a['path'] <=> $b['path'];
});

然后通过 path:

递归嵌套项目
function nest(&$directory)
{
    for ($i = 0; $i < count($directory); $i++)
    {
        while ($i + 1 < count($directory) && strpos($directory[$i + 1]['path'], $directory[$i]['path'] . '/') === 0)
        {
            $directory[$i]['contents'][] = $directory[$i + 1];
            array_splice($directory, $i + 1, 1);
        }

        nest($directory[$i]['contents']);
    }
}

在不区分大小写的文件系统上(例如 Windows),您可能希望将 strpos() 替换为 stripos(),但我没有对此进行测试,所以我将其留给您决定。

如果您能够改用对象数组,则可以利用像引用一样传递对象的方式来简化这种结构的创建。

sort($inputArray);

foreach ($inputArray as $item) {
    $item = (object) $item;
    $files[$item->path] = $item;
    $files[substr($item->path, 0, strrpos($item->path, '/'))]->contents[] = $item;
}

$result = reset($files);

如果对象不适合您,JSON encode/decode 可以将结果中的对象转换为数组。

$result = json_decode(json_encode($result), true);