mysql — массив списков файлов php в дерево массивов

У меня есть несколько массивов списков файлов с числом элементов более 100, которые мне нужно преобразовать в массив деревьев, вставить их в базу данных и вернуть дерево по вызову для системы каталогов json api.
Я провел неделю, пробуя разные алгоритмы, все они в какой-то момент терпят неудачу.
Это массив:

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

первый элемент — путь к файлу, второй — размер файла.
Эти файлы не существуют на этом сервере, они находятся на другом сервере, это сервер API.
Мне нужно преобразовать его в массив вложенного дерева, как это:

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
)

)

Я написал некоторый код, но он поднимается только до 2-го уровня (dir2), затем на третьем уровне (dir3) он не работает должным образом.

код:

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

Этот код прекрасно возвращает массив, если я удаляю уровень dir3 из массива списка файлов, но при наличии dir3 он дает:

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
)

)

Это [dir1 / dir2] — проблема, мне нужно, чтобы оно было идеальным деревом, чтобы я мог повторить его и вставить записи в базу данных.

0

Решение

Поскольку вы не знаете глубину дерева заранее, вы не можете управлять этим с помощью циклов if / else. Это вариант использования, который требует рекурсии.

<?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>';

Видите ли, я вызываю функцию по заданному пути. Для каждой записи на этом пути я

  • Откажитесь. а также ..
  • Если это папка, узел будет содержать результат применения этой функции к подпути
  • В любом другом случае узел будет содержать размер файла

Вам нужно будет изменить мой код в соответствии с вашими потребностями. Я могу сказать, что ваш случай «это файл или ссылка» имеет другой формат.

РЕДАКТИРОВАТЬ: поскольку нет реальной структуры файлов для сканирования, но вместо этого у вас есть массив путей, это решение, с которым я пришел

<?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>';

Я разбирал каждый путь, используя косую черту в качестве разделителя, затем повторял путь по пути папка за папкой, пока не дошел до финальной части, и рекурсия заканчивалась именем и размером файла.

0

Другие решения

Вот мой путь

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

По вопросам рекламы [email protected]