我已经对这个问题感到困惑了好几天,没有任何运气。我希望你们中的一些人能提供帮助。从我的数据库中,我得到了一个文件列表,其中附加了各种信息,包括虚拟路径。一些典型的数据是:
Array
(
[0] => Array
(
[name] => guide_to_printing.txt
[virtual_path] => guides/it
)
[1] => Array
(
[name] => guide_to_vpn.txt
[virtual_path] => guides/it
)
[2] => Array
(
[name] => for_new_employees.txt
[virtual_path] => guides
)
)
我希望将其从虚拟路径转换为分层数组结构,因此上述输出应为:
Array
(
[0] => Array
(
[type] => dir
[name] => guides
[children] => Array
(
[0] => Array
(
[type] => dir
[name] => it
[children] = Array
(
[0] => Array
(
[type] => file
[name] => guide_to_printing.txt
)
[1] => Array
(
[type] => file
[name] => guide_to_vpn.txt
)
)
)
[1] => Array
(
[type] => file
[name] => for_new_employees.txt
)
)
)
)
其中 type 属性指示它是目录还是文件。
有人可以帮助创建一个执行此转换的函数吗?这将有很大的帮助。谢谢。
到目前为止,我自己的最佳解决方案是:
foreach($docs as $doc) {
$path = explode("/",$doc['virtual_path']);
$arrayToInsert = array(
'name' => $doc['name'],
'path' => $doc['virtual_path'],
);
if(count($path)==1) { $r[$path[0]][] = $arrayToInsert; }
if(count($path)==2) { $r[$path[0]][$path[1]][] = $arrayToInsert; }
if(count($path)==3) { $r[$path[0]][$path[1]][$path[2]][] = $arrayToInsert; }
}
当然,这仅适用于目录结构中 3 的深度,键是目录名称。
函数
function hierarchify(array $files) {
/* prepare root node */
$root = new stdClass;
$root->children = array();
/* file iteration */
foreach ($files as $file) {
/* argument validation */
switch (true) {
case !isset($file['name'], $file['virtual_path']):
case !is_string($name = $file['name']):
case !is_string($virtual_path = $file['virtual_path']):
throw new InvalidArgumentException('invalid array structure detected.');
case strpos($virtual_path, '/') === 0:
throw new InvalidArgumentException('absolute path is not allowed.');
}
/* virtual url normalization */
$parts = array();
$segments = explode('/', preg_replace('@/++@', '/', $virtual_path));
foreach ($segments as $segment) {
if ($segment === '.') {
continue;
}
if (null === $tail = array_pop($parts)) {
$parts[] = $segment;
} elseif ($segment === '..') {
if ($tail === '..') {
$parts[] = $tail;
}
if ($tail === '..' or $tail === '') {
$parts[] = $segment;
}
} else {
$parts[] = $tail;
$parts[] = $segment;
}
}
if ('' !== $tail = array_pop($parts)) {
// skip empty
$parts[] = $tail;
}
if (reset($parts) === '..') {
// invalid upper traversal
throw new InvalidArgumentException('invalid upper traversal detected.');
}
$currents = &$root->children;
/* hierarchy iteration */
foreach ($parts as $part) {
while (true) {
foreach ($currents as $current) {
if ($current->type === 'dir' and $current->name === $part) {
// directory already exists!
$currents = &$current->children;
break 2;
}
}
// create new directory...
$currents[] = $new = new stdClass;
$new->type = 'dir';
$new->name = $part;
$new->children = array();
$currents = &$new->children;
break;
}
}
// create new file...
$currents[] = $new = new stdClass;
$new->type = 'file';
$new->name = $name;
}
/* convert into array completely */
return json_decode(json_encode($root->children), true);
}
例
案例1:
$files = array(
0 => array (
'name' => 'b.txt',
'virtual_path' => 'A/B//',
),
1 => array(
'name' => 'a.txt',
'virtual_path' => '././A/B/C/../..',
),
2 => array(
'name' => 'c.txt',
'virtual_path' => './A/../A/B/C//////',
),
3 => array(
'name' => 'root.txt',
'virtual_path' => '',
),
);
var_dump(hierarchify($files));
将输出...
array(2) {
[0]=>
array(3) {
["type"]=>
string(3) "dir"
["name"]=>
string(1) "A"
["children"]=>
array(2) {
[0]=>
array(3) {
["type"]=>
string(3) "dir"
["name"]=>
string(1) "B"
["children"]=>
array(2) {
[0]=>
array(2) {
["type"]=>
string(4) "file"
["name"]=>
string(5) "b.txt"
}
[1]=>
array(3) {
["type"]=>
string(3) "dir"
["name"]=>
string(1) "C"
["children"]=>
array(1) {
[0]=>
array(2) {
["type"]=>
string(4) "file"
["name"]=>
string(5) "c.txt"
}
}
}
}
}
[1]=>
array(2) {
["type"]=>
string(4) "file"
["name"]=>
string(5) "a.txt"
}
}
}
[1]=>
array(2) {
["type"]=>
string(4) "file"
["name"]=>
string(8) "root.txt"
}
}
案例2:
$files = array(
0 => array (
'name' => 'invalid.txt',
'virtual_path' => '/A/B/C',
),
);
var_dump(hierarchify($files));
会扔...
Fatal error: Uncaught exception 'InvalidArgumentException' with message 'absolute path is not allowed.'
案例3:
$files = array(
0 => array (
'name' => 'invalid.txt',
'virtual_path' => 'A/B/C/../../../../../../../..',
),
);
var_dump(hierarchify($files));
会扔...
Fatal error: Uncaught exception 'InvalidArgumentException' with message 'invalid upper traversal detected.'
像这样:
foreach ($array as $k => $v) {
$tmp = explode('/',$v['virtual_path']);
if(sizeof($tmp) > 1){
$array_result[$tmp[0]]['children'][$k]['type'] = 'file';
$array_result[$tmp[0]]['children'][$k]['name'] = $v['name'];
$array_result[$tmp[0]]['type'] = 'dir';
$array_result[$tmp[0]]['name'] = $v['name'];
}
}
我得到一个这样的数组:
Array
(
[guides] => Array
(
[children] => Array
(
[0] => Array
(
[type] => file
[name] => guide_to_printing.txt
)
[1] => Array
(
[type] => file
[name] => guide_to_vpn.txt
)
)
[type] => dir
[name] => guide_to_vpn.txt
)
)
我知道这不是你想要的,但我认为这可以让你朝着正确的方向前进。
事件 虽然你应该在这里发帖之前尝试一些东西,但我喜欢你的问题,并认为这是一个有趣的问题。所以你去吧
function &createVirtualDirectory(&$structure, $path) {
$key_parts = $path ? explode('/', $path) : null;
$last_key = &$structure;
if (is_array($key_parts) && !empty($key_parts)) {
foreach ($key_parts as $name) {
// maybe directory exists?
$index = null;
if (is_array($last_key) && !empty($last_key)) {
foreach ($last_key as $key => $item) {
if ($item['type'] == 'dir' && $item['name'] == $name) {
$index = $key;
break;
}
}
}
// if directory not exists - create one
if (is_null($index)) {
$last_key[] = array(
'type' => 'dir',
'name' => $name,
'children' => array(),
);
$index = count($last_key)-1;
}
$last_key =& $last_key[$index]['children'];
}
}
return $last_key;
}
$input = array(
0 => array (
'name' => 'guide_to_printing.txt',
'virtual_path' => 'guides/it',
),
1 => array(
'name' => 'guide_to_vpn.txt',
'virtual_path' => 'guides/it',
),
2 => array(
'name' => 'for_new_employees.txt',
'virtual_path' => 'guides',
)
);
$output = array();
foreach ($input as $file) {
$dir =& createVirtualDirectory($output, $file['virtual_path']);
$dir[] = array(
'type' => 'file',
'name' => $file['name']
);
unset($dir);
}
print_r($output);
提供您想要的确切输出
这是使用 2 个递归函数执行此操作的简单方法。一个函数来解析一行数据。另一个用于合并每个解析的数据行。
// Assuming your data are in $data
$tree = array();
foreach ($data as $item) {
$tree = merge($tree, parse($item['name'], $item['virtual_path']));
}
print json_encode($tree);
// Simple parser to extract data
function parse($name, $path){
$parts = explode('/', $path);
$level = array(
'type' => 'dir',
'name' => $parts[0],
'children' => array()
);
if(count($parts) > 1){
$path = str_replace($parts[0] . '/', '', $path);
$level['children'][] = parse($name, $path);
}
else {
$level['children'][] = array(
'type' => 'file',
'name' => $name
);
}
return $level;
}
// Merge a new item to the current tree
function merge($tree, $new_item){
if(!$tree){
$tree[] = $new_item;
return $tree;
}
$found = false;
foreach($tree as $key => &$item) {
if($item['type'] === $new_item['type'] && $item['name'] === $new_item['name']){
$item['children'] = merge($item['children'], $new_item['children'][0]);
$found = true;
break;
}
}
if(!$found) {
$tree[] = $new_item;
}
return $tree;
}