Necessity of data output structured in the form of trees appears by writing your own forum or sites� catalogue. There is a lot of finished catalogues and forums in the net but they doesn�t suit and rewriting something written by someone else will take much more time than writing something of your own.
You�d better take common structure as an entry of a message or forum�s rubric contains parent�s identifier. Recursive function offers itself for the tree output organization. Exactly this was done in Phorum. File include/multi-threads.php contains thread function which is aroused for each root message and recursively arouses itself to answer them:
<?php
function thread ($seed = 0) {
...

if(@
is_array($messages[$seed]["replies"])) {
$count = count($messages[$seed]["replies"]);
for(
$x = 1;$ x <= $count; $x++) {
$key = key($messages[$seed]["replies"]);
thread ($key);
next ($messages[$seed]["replies"]);
}
}
}
?>
But arousing recursive function by the output makes me doubt: repeated message tree building by each output seems to be irrational to me. Structure of a tree changes only by adding, changing and removing messages. It would be better to arouse the given procedure by such actions, save the structure in a table and evade any calculations by the output of a tree.
To build a tree it�s enough to know the succession of rubrics� output and their level in the tree. We add two fields with this data into the table: level (TINYINT(4). 127 levels are enough?) and sortorder (VARCHAR(128)).

All we need to build a tree is rubric�s and its parent�s identifiers. Imagine we�ve got some rubrics with such content in our catalogue:
The tree structure which image we�d like to get is shown above:
But the given algorithm will enable us to draw a tree without branch-formed lines as it is done on the picture. The tree structure will be drawn by means of indentions from the left.
Let�s return once more to the id-parent table. These rubrics have been already sorted on some basis on which we want to sort the equal level elements. For example on falling sites� numbers. Beside id and parent�s rubric we know number of each of them in the given list. We equalize them up to the necessary length by adding zeros from the left. After that we make for each rubric a text line with all its parents� numbers beginning from the very root:
By sorting on the sortorder field we�ll exactly what we need:

Left indent is done taking into account level field.
It�s important to mention that we are not to sort anything in the script itself. For forming fields sortorder and level you are to prevent table from recording (in order to evade changes in the branches structure), select from the base rubric�s and its parent�s identifier by sorting on the necessary basis and write them into a simple two-dimensional massive. Then you are to treat the massive in succession from the first to the last level and write down fields sortorder and level into the table.
You don�t need recursion for forming sortorder (although you may and probably it will work even faster). It�s enough to treat the massive with the same cycle. If the rubric isn�t finished, field sortorder from field sort and parent�s sortorder will be formed for it there. If the parent�s rubric isn�t treated yet, flag $unprocessed_rows_exist arouses and the cycle restarts.
<?php
mysql_query
("LOCK TABLES dir WRITE");

$result = mysql_query("SELECT id, IFNULL(parent,0) as parent FROM dir
ORDER BY sites DESC, title"
);

while (
$row = mysql_fetch_array($result)) {
$count++;
$data["parent"][$row["id"]] = $row["parent"];
$data["sort"][$row["id"]] = $count;
}

reset($data);

$unprocessed_rows_exist = true;
while(
$unprocessed_rows_exist) {
$unprocessed_rows_exist = false;
while (list(
$i, $v) = each($data["parent"])) {
if((
$data["parent"][$i] == 0 || !isset($data["sort"][$data["parent"][$i]]))
&& !isset(
$data["sortorder"][$i])) {
$data["sortorder"][$i] = str_pad($data["sort"][$i], $max, "0", STR_PAD_LEFT);
$data["level"][$i] = 0;
}
elseif(!isset(
$data["sortorder"][$i]) &&
isset(
$data["sortorder"][$data["parent"][$i]])) {
$data["sortorder"][$i] = $data["sortorder"][$data["parent"][$i]].
str_pad($data["sort"][$i], $max, "0", STR_PAD_LEFT);
$data["level"][$i] = $data["level"][$data["parent"][$i]] + 1;
}
elseif(!isset(
$data["sortorder"][$i]) && isset($data["sort"][$data["parent"][$i]])) {
$unprocessed_rows_exist = true;
}
}

reset($data);
?>
It�s worth to mention that given algorithm doesn�t get caught into an endless loop at the presence of lines with beaten parent field and doesn�t let them through but makes them to the root ones. Recursive algorithm will simply let them through.
After having finished this cycle we have massives "id => level" and "id => sortorder". We send the only request to the base using inner functions MySQL ELT and FIND_IN_SET:
<?php mysql_query("UPDATE dir SET sortorder=ELT(FIND_IN_SET
(id,"". implode("
,", array_keys($data["sortorder"])). ""),". implode(",", $data["sortorder"]). ")
, level=ELT(FIND_IN_SET(id,"". implode("
,", array_keys($data["level"])). ""),".
implode(",", $data["level"]). ")
WHERE id IN ("
. implode(",", array_keys($data["sortorder"])). ")"); ?>