The Tree class can render tree structures such as directory hierarchies and menu structures as HTML. The structure must be given to Tree as an nested array of arrays of arbitrary depth.
The idea of Tree is, that there are several mathematical models a tree could be viewed: One model is a data structure like nested arrays or a pointer structure from where you can print multidimensional graphics and can do other neat things like deleting one part of the tree or inserting a whole subtree. But you can also imagine a tree as a one dimensional string or as a sequence of function calls (which is nearly the same in the mathematical sense).
To generate HTML-code from a tree-structure it is like this: You need at the
end a one-dimensional string, which tells the browser what to do. The
Tree class assists you in generating this string in this way, that it will go
through the whole tree and call several functions on every stage trough the
way. It will be your task to change the functions, so that a nice layout will
be generated.
This function is completely user driven! You have to create an
array with the structure described below. See the example
for details.
Don't be shy to create some own functions which are called by
go_trough_tree($key="",$path="",$depth=0,$lcount=0,$pcount=0)
This is the most important function of this class. It will call the output
functions in the right order with the correct parameters.
All variables are optional. The parameters are perhaps useful, if you
want to display only partial trees, but this is not supported now.
This function is mostly used internally, but could be useful
for you to generate
Example:
This function isn't used internally, but could be useful
for you during generating the output tree. It will remove
one from the depth of the path.
Example:
This function is the 'non-call-by-reference-version' of
path_sub ($path)
This function is the 'non-call-by-reference-version' of
path_index ($path)
This function is the 'non-call-by-reference-version' of
starttree ()
This function is called by
All growtree ($key,$value,$path,$depth,$count,$pcount)
This function is called by leaftree ($key,$value,$path,$depth,$count,$pcount)
This function is called, when the current item has shrinktree ($key,$depth)
This function is the "opposite" of endtree()
Called when leaving tree.
As said above, before you call
One little quirk has to be explained, because it is a little
bit confusing: the array name 0 (zero) is used for the value of the
parent element. As shown in the example, an element with children
(for example "etc") cannot have attributes (such as "allowed").
Instead the value of this element is stored in a pseudo-child
named 0. If this element is not present, it will have the value
"Array" (perhaps something that should be changed).
The output of this example if you don't change the output-functions will
look like this:
My example is just going trough the directory structure of your hard disk.
The following code could read it:
There is one known bug: If a name of a subpath contains the
The same thing is with the value [0] (zero) of a sub-array. This element
is always used as the attribute of the parent element.
A good tip: when you
build your tree recursively then the [0]-index must be filled
Also it is possible that not every name could be inserted into the
associate index-field (Control-chars etc.), but this is untested.
$t->delimiter="/";
$path= "usr/local/lib";
## $path must be given as a var, because it is called by reference!
$bla = $t->path_to_index($path,"etc");
## $path is now "usr/local/lib/etc"
## $bla is now ["usr"]["local"]["lib"]["etc"]
$t->delimiter="/";
$path= "usr/local/lib";
$bla = $t->path_to_parent($path);
## $path is now "usr/local"
## $bla is now ["usr"]["local"]
$t= new Tree;
$t->tree = array(
"usr" => array(
0 => "allowed",
"lib" => "forbidden",
"local" => "allowed",
"bin" => "forbidden",
"etc" => array(
0 => "allowed",
"hosts" => "forbidden",
"mailcap"=> "allowed"
),
"var" => "allowed",
"tmp" => "allowed"
),
"root" =>"forbidden"
);
$t->go_through_tree();
print $t->outp;
This is a completely recursive structure and I think, it is clear, how
to create it with a recursive call of a function. If not, see the
example below.
/
^---- usr->'allowed' : 'usr' (1) [1/2]
| ^---- lib->'forbidden' : 'usr^lib' (2) [2/7]
| O---- local->'allowed' : 'usr^local' (2) [3/7]
| O---- bin->'forbidden' : 'usr^bin' (2) [4/7]
| O---- etc->'allowed' : 'usr^etc' (2) [5/7]
| | ^---- hosts->'forbidden' : 'usr^etc^hosts' (3) [2/3]
| | \--- mailcap->'allowed' : 'usr^etc^mailcap' (3) [3/3]
| O---- var->'allowed' : 'usr^var' (2) [6/7]
| \--- tmp->'allowed' : 'usr^tmp' (2) [7/7]
\--- root->'forbidden' : 'root' (1) [2/2]
class dir_Tree extends Tree {
var $classname = "dir_Tree";
var $delimiter="/";
var $tdat;
function build_tree ($path=".") {
$this->tree=$this->recurs_dir($path,0);
}
## This example code can read and output 1000 directory entries with
## many subdirs in about 20 seconds on my system (P200, 64 MB);
## 220 dir entries with a maximum depth of 4 are read in 2 seconds.
## This is ok. :)
function recurs_dir ($path,$depth) {
GLOBAL $flap_out;
$d=opendir($path);
while ( $name=readdir($d) ) {
$pathname=$path . $this->delimiter . $name;
if (is_dir($pathname) && !ereg("\.\.?",$pathname)) {
if (isset($flap_out[$pathname])) {
$array[$name]=$this->recurs_dir($pathname,$depth+1);
}
# ATTENTION: It is IMPORTANT fill the [0] array
# *after* filling the rest of the array!
$array[$name][0]=$pathname;
} else {
$array[$name]=$pathname;
}
}
closedir($d);
return($array);
}
#################################################
## FLAPPING IN and OUT
## This is used to create an array which includes
## all sub-paths which should be showed
##
function flapping ($path) {
GLOBAL $flap_out;
if ($path) {
if (is_dir($path)) {
if (isset($flap_out[$path])) {
unset($flap_out[$path]);
} else {
$flap_out[$path]=$name;
}
}
}
}
}
$t= new dir_Tree;
$t->flapping($val); ## $val is given by GET-method, see *tree()-functions
$t->build_tree();
$t->go_through_tree();
print $t->outp;