Forum Moderators: coopster
I shall now unveil my magnificent octopus ;) and invite all you clever peeps to help me resolve my remaining issues...
The Code..
//get the url, and trim off the first slash in order to avoid extra value in array later on
$url = substr($_SERVER['PHP_SELF'],1);
//use explode to find out what section we're in
$urlarray = explode("/", $url);
//how many levels deep are we?
$levelsdeep=(count($urlarray));
//current directory
$dirpath = "./";
//selecteddirectory
$seldirpath = $dirpath;
$countlevelsdeep = $levelsdeep;
//do this for current directory
while($countlevelsdeep>0){
$dh = opendir($seldirpath);
//loop through the contents
while (false!== ($file = readdir($dh))) {
//list only subdirectories
if (is_dir("$seldirpath/$file")) {
//put them in an array
$dirarray[] = $file;
}
}
closedir($dh);
//remove any items we don't want from our array
$deletekey = array_search('css', $dirarray);
unset($dirarray[$deletekey]);
$deletekey = array_search('Templates', $dirarray);
unset($dirarray[$deletekey]);
$deletekey = array_search('includes', $dirarray);
unset($dirarray[$deletekey]);
$deletekey = array_search('.', $dirarray);
unset($dirarray[$deletekey]);
$deletekey = array_search('..', $dirarray);
unset($dirarray[$deletekey]);
//save as new array each time
$menuarray[] = $dirarray;
unset($dirarray);
//-increment level
$countlevelsdeep--;
//add level to dir path
$seldirpath.="../";
}
echo("<pre>");
print_r($menuarray);
echo("</pre>");
$menuint = $levelsdeep;
//loop through the levels
while($menuint>=0){
echo('<ul id="'.$menuint.'">');
//get rid of any empty arrays
if($menuarray[$menuint]!=""){
foreach ($menuarray[$menuint] as $key){
echo('<li><a href="'.$key.'">'.$key.'</a></li>');
}
}
echo("</ul>");
$menuint--;
}
The Problems...
Firstly, I have an extra empty array - why is this?
Secondly, I need to make my menu have proper links which actually work!
Thirdly if anyone can see anything stoopid or long winded I'm doing, feel free to point it out!
Cheers :)
[edited by: HelenDev at 4:13 pm (utc) on June 6, 2007]
these arrays are done in ascending (up the tree) order and the menu is done in descending (down the tree) order
interesting, pretty quick too, testing it on a medium size site, not bad
<added>did you want to do them in more of a tree structure and tie the levels to their upper level items?
<added>did you want to do them in more of a tree structure and tie the levels to their upper level items?
I can't speak for Helen, but I think making that adjustment to the array structure would be the best way to make the outputting of correct links easiest.
I have a similar script that does a sitemap and portions of it would work for the this
<added>I also thought you could add some sorting if you wanted the links alphabetical, though you may not want that.
The other issue is you might want to set an exclusion array so that directories that you don't want listed would be skipped
I also did not get empty arrays, except when they *should* be empty due to a lack of subdirectories at a particular level. You'll see the links are now correct because of the whole
$current_working_directorynonsense at the beginning of the
while($countlevelsdeep>0)loop.
As far as long winded, I took out an unneeded loop by testing for excluded directories before putting the directory into the
$dirarrayin the first place. I also used the
in_array()approach to that task as discussed here [webmasterworld.com] to make the code shorter.
Overall, I would prefer to rewrite it to build a multidimensional array but it's still too early in the morning for me to wrap my ahead around that. ;)
<?php
//get the url, and trim off the first slash in order to avoid extra value in array later on
$url = substr($_SERVER['PHP_SELF'],1);
echo '<br />$url: '.$url;
//use explode to find out what section we're in
$urlarray = explode("/", $url);
$urlarray_rev = array_reverse($urlarray);
//how many levels deep are we?
$levelsdeep=(count($urlarray));
echo '<pre>'; print_r($urlarray_rev); echo '</pre>';
//current directory
$dirpath = "./";
//selecteddirectory
$seldirpath = $dirpath;
$countlevelsdeep = $levelsdeep;
//do this for current directory
while($countlevelsdeep>0){
$upDir = ($levelsdeep-$countlevelsdeep+1);
$current_working_directory = $urlarray_rev[$upDir].'/';
while( $upDir++ < $levelsdeep ){
$current_working_directory = $urlarray_rev[($upDir)].'/'.$current_working_directory;
}
$dh = opendir($seldirpath);
//loop through the contents
$hidden_directories = array( 'css', 'Templates', 'includes' );
while (false!== ($file = readdir($dh))) {
//list only subdirectories
if (is_dir("$seldirpath/$file")) {
//put them in an array
//echo '<br />'.$file;
if( $file{0}!= '.' &&!in_array($file, $hidden_directories))
$dirarray[$current_working_directory][] = $file;
}
}
closedir($dh);
//-increment level
$countlevelsdeep--;
//add level to dir path
$seldirpath.="../";
}
ksort($dirarray);
echo("<pre>");
print_r($dirarray);
echo("</pre>");
foreach($dirarray as $dir=>$dirs){
//get rid of any empty arrays
if(is_array($dirs) && count($dirs) >= 1){
echo('<ul id="'.str_replace('/','.',$dir).'">');
foreach ($dirs as $d){
echo '<li><a href="'.$dir.''.$d.'/">'.$dir.''.$d.'/</a></li>';
}
echo("</ul>");
}
$menuint--;
}
?>
I also did not get empty arrays, except when they *should* be empty due to a lack of subdirectories at a particular level
I think that's what it was, and I was tired and confused at that point!
I took out an unneeded loop by testing for excluded directories
Thanks, I was thinking I probably needed to do something like that.
I also thought you could add some sorting if you wanted the links alphabetical, though you may not want that
That would probably be useful. How are they ordered by default?
The only other thing I would want to add to this, is to tidy up my menu items. I have taken out the $dir and / from the <li> and will look to strip out any underscores and replace with spaces. I would also like to have the section names in title case (capitalized), with any mini-words (and, it etc.) excluded from this.
I'll go away and work on this...
Thanks for all your help so far, I'm pleased with how it's turning out :)
I'm now back in the real world, trying to style my menu for actual use. I made a few small amends to the code, but am wondering if it needs any fundamental changes, such as the 2 dimensional array which you were all talking about.
Basically I would like to have IDs and classes so that I can make the menu item for this-page, this-pages-parent and this-pages-children all look as they should.
Also, I think it is common in most menus for the child items to appear directly underneath the parent page - at the moment they are appearing at the bottom, which could be a bit odd.
Does anyone have any bright ideas as to the simplist way to achieve this?
//domain
$domain = "http://www.mydomain.co.uk";
//get the url, and trim off the first slash in order to avoid extra value in array later on
$url = substr($_SERVER['PHP_SELF'],1);
//use explode to find out what section we're in
$urlarray = explode("/", $url);
//how many levels deep are we?
$levelsdeep=(count($urlarray));
if ((count($urlarray))>3){
//need to remove some levels from this until files in correct place
$countlevelsdeep = $levelsdeep-3;
while($countlevelsdeep>0){
$prefixpath.="../";
$countlevelsdeep--;
}
}
//create a reliable path to be used for include files and such
$incpath="includes/";
$filepath = $prefixpath.$incpath;
$imgpath="images/";
$imgfilepath = $prefixpath.$imgpath;
//titlecase function
function titleCase($mystring){
//turn string into array
$mystringarray = explode("_", $mystring);
// exclude mini words
$miniwords = array('and', 'for', 'of');
foreach($mystringarray as $i => $word){
if(!in_array($word, $miniwords)){
$mystringarray[$i] = ucwords($word);
}
}
//turn array back into string but with spaces between each value
$mystring = implode(" ", $mystringarray);
return $mystring;
}
//remove index.php (last key) from array
$lastkey = end(array_keys($urlarray));
unset($urlarray[$lastkey]);
//put the breadcrumb values and links in an array for later use with menu
$breadcrumbarray = array();
foreach($urlarray as $value){
$breadpath.='/'.$value;
$breadcrumbarray[$domain.$breadpath]=$value;
}
//trim root off breadcrumbarray
$root = array_shift($breadcrumbarray);
$breadcrumb = '<a href="http://www.mydomain.co.uk">My Site</a> > <a href="http://www.mydomain.co.uk/intranet/">Internal</a>';
foreach($breadcrumbarray as $key => $value){
$breadcrumb.=' > <a href="'.$key.'">'.titleCase($value).'</a>';
}
$linkarray = $breadcrumbarray;
//end($linkarray) = current location
$current_location = end($linkarray);
//don't show folders with these names
$hidden_directories = array( '.', '..', 'css', 'Templates', 'includes', 'images', 'js', 'icaew', 'documents');
echo('<ul>');
//top level menu
//root directory - need to calcualte this each time
$rootdir = $prefixpath."../";
// open the top level directory
if ($dh = opendir($rootdir)) {
while (($file = readdir($dh))!== false) {
if (is_dir("$rootdir/$file") &&!in_array($file, $hidden_directories)) {
//check if this is current section
if($file == $urlarray[1]){
//check if this is also the current location, and if it is, don't show the link
if($urlarray[1]!= $current_location){
echo ('<li id="current_section"><a href="../'.$prefixpath.$file.'">'.$file.'</a></li>');
}
//list parent, grandparent etc.
$menulinkarray = $linkarray;
//unset first and last values
$remove_section = array_shift($menulinkarray);
$lastmenukey = end(array_keys($menulinkarray));
unset($menulinkarray[$lastmenukey]);
foreach($menulinkarray as $key => $value){
echo('<li class="ancestors"><a href="'.$key.'">'.titleCase($value).'</a></li>');
}
//current item
echo('<li id="current_location">'.titleCase($current_location).'...</li>');
//if current item has any child directories, list them
$currentdir = "./";
if (is_dir($currentdir)) {
if ($currentdh = opendir($currentdir)) {
while (($file = readdir($currentdh))!== false) {
if (is_dir("$currentdir/$file") &&!in_array($file, $hidden_directories)) {
echo ('<li class="child_items"><a href="'.$file.'">'.titleCase($file).'</a></li>');
}
}
closedir($currentdh);
}
}
} else {
echo ('<li class="top_level"><a href="../'.$prefixpath.$file.'">'.$file.'</a></li>');
}
}
}
}
closedir($dh);
echo('</ul>');
And then of course we can add some styles (of course you can make them prettier than these!)...
#menu{width:25%; float:left;}
.top_level{margin-left:-10px;}
#current_section{font-weight:bold; background-color:#FFFF00;}
#current_location{font-weight:bold;}
.child_items{margin-left:20px; background-color:#00FFFF;}
.ancestors{background-color:#99FF99}
#menu a{text-decoration:none;}
#menu a:hover{text-decoration:underline;}
Please feel free to try it on your sites and let me know what you think or if you spot any issues.
Thanks :)
This is how far I've got, but being a bit new to functions, I don't think it's quite right and it's not working...
//don't show folders with these names
$hidden_directories = array( '.', '..', 'css', 'Templates', 'includes', 'images', 'js', 'icaew', 'documents');
//create function to read files in directory, put them in an array and order it alphabetically
function readDirList($thisdir,$thisdirname){
if (is_dir($thisdir)) {
if ($thisdh = opendir($thisdir)) {
//create array
$thisarray = array();
while (($file = readdir($thisdh))!== false) {
if (is_dir("$thisdir/$file") &&!in_array($file, $hidden_directories)) {
$thisarray[] = $file;
}
}
}
closedir($thisdh);
}
sort($thisarray); //puts an array in alphabetical order
}
readDirList("./","current_directory");
It needs to be reusable for the current directory, the parent directory, and any child directory, and it needs to create a different array for each, as before.
//create function to read files in directory, put them in an array and order it alphabetically
function readDirList($thisdir){
//don't show folders with these names
$f_hidden_directories = array( '.', '..', 'css', 'Templates', 'includes', 'images', 'js', 'icaew', 'documents');
if (is_dir($thisdir)) {
if ($thisdh = opendir($thisdir)) {
$thisarray = array();
while (($file = readdir($thisdh))!== false) {
if (is_dir("$thisdir/$file") &&!in_array($file, $f_hidden_directories)) {
$thisarray[] = $file;
}
}
}
closedir($thisdh);
}
sort($thisarray); //puts an array in alphabetical order
return $thisarray;
}