...

View Full Version : "File Tree" using Select Box(s)



mtd
06-05-2005, 05:31 AM
Hello! I'm trying to create a "file tree" of sorts using select (drop-down) boxes. Does anyone know of any pre-existing code that accomplishes this, or willing to lend a hand? I have given it a try but am as of yet unsuccesful.

If a file is selected, I need the filename to pass as a variable. If a folder is selected, I need it to display that folder's contents in the selectbox. One select box can be used, or multiple ones (I'm not picky). I do need to define a starting folder and have it "capped off" - meaning the user cannot navigate any closer to the root as that defined folder.

This is what I have attempted so far:
if (!isset($root_directory)) {
$root_directory = "/var/www/html/mtd/test/";
}

// BUILD FILE SELECTION MENU
function print_file_selection($root_dir) {
global $search_this_file;
global $root_directory;
echo "<select name=\"search_this_file\">";
$dh = opendir($root_dir) or die("Couldn't open specified directory.");
while (!(($file = readdir($dh)) === false ) ) {
if ($file != "..") {
echo "<option value=\"".$file."\" class=\"file\"";
if ($file == $search_this_file) {
echo " selected";
}
echo ">".$file."</option>";
}
}
closedir($dh);
echo "</select>";
}

// DETIRMINE FILE OR FOLDER, SEND CORRESPONDING VALUE
function determine_type() {
global $search_this_file;
global $root_directory;
if (is_dir($search_this_file)) {
$root_directory = $root_directory.$search_this_file."/";
}
print_file_selection($root_directory);
echo "<input type=\"hidden\" value=\"".$root_directory."\" name=\"root_directory\">";
echo "<input type=\"submit\" value=\"Open\">";
} ...but when I get past the first root folder, I can't seem to save the new root - trying to do anything just brings me back to the original folder.

Fou-Lu
06-05-2005, 05:53 AM
I'm under the impressions you would like to list all of these correct, from the folder of your choice down, including all files as well as directories and sub-directories?
Here's what I mean, a simple text version:


-{Your chosen root}
--Index.php
--comments.php
--New Directory
----Index.php
--mail.php

Sort of in that fasion with a select box?
I'll see what I can do for you a little later, this is more complicated than it seems. Just confirm that that is what you are looking for, and I'll see if I can throw it together in the morning.

dumpfi
06-05-2005, 08:59 AM
Give this a try:
<?php
define('ROOT_DIRECTORY', realpath('var/www/html/mtd/test/'));
function printFileSelection($relDir) {
$absDir = realpath(ROOT_DIRECTORY.'/'.$relDir);
echo '<select name="search_this_file">';
// don't let the user go closer to the root than ROOT_DIRECTORY
if(strpos(ROOT_DIRECTORY, $absDir) !== FALSE || !$absDir) $absDir = ROOT_DIRECTORY;
// let the user go "up" if he's not at the ROOT_DIRECTORY
else echo '<option value="/..">Go Up</option>';
// if a directory is selected show the files
if(is_dir($absDir)) {
$dir = dir($absDir);
while(($entry = $dir->read()) !== FALSE) {
if($entry == '.' || $entry == '..') continue;
echo '<option value="',substr($absDir, strlen(ROOT_DIRECTORY)),$entry,'" class="file">',$entry,(is_dir($absDir.'/'.$entry)) ? ' -->' : '','</option>';
}
$dir->close();
}
echo '</select>';
}
echo '<form action="',getenv('SCRIPT_NAME'),'" method="get">';
$relDir = (isset($_GET['search_this_file'])) ? $_GET['search_this_file'] : '';
printFileSelection($relDir);
echo '<input type="submit" value="Open"></form>';
?>dumpfi

mtd
06-05-2005, 12:40 PM
Fou-Lu, that is pretty much exactly what I had in mind. Dumpfi hit the nail on the head, but the root directory definition does not work (it starts at the real server root no matter what is entered) - I'm working on that now. But that was exactly what I was looking for in concept.

FYI to make the folder progression work, the following change is needed in the code above:

ORIGINAL line 15:
echo '<option value="',substr($absDir, strlen(ROOT_DIRECTORY)),$entry,'" class="file">',$entry,(is_dir($absDir.'/'.$entry)) ? ' -->' : '','</option>';
CORRECT line 15:
echo '<option value="',substr($absDir, strlen(ROOT_DIRECTORY)),'/',$entry,'" class="file">',$entry,(is_dir($absDir.'/'.$entry)) ? ' -->' : '','</option>';Note the added ,'/', between (ROOT_DIRECTORY)) and $entry,'"


Now, aside from the root directory definition not working, when I get to a *file* in the select box, it passes the variable fine, but the select box still thinks it's reading a *folder*, and ends up displaying an empty box with the "Go Up" option bringing you all the way back to the root, rather than one level up. Is there a way to keep the select box on the file's folder when it is selected, rather than having it try to display the file as a folder? I imagine there is an is_file / is_dir option I can throw in somewhere, but I'm not quite sure how or where...

Anyway, thanks for your help so far! even with these problems, I'm 100x farther than I would have been without help!

devosc
06-05-2005, 05:39 PM
I tried reworking Chris Wong algorithm posted on php.net for the manual page of dir read... but the problem is that it now needs to sort the listings (alphabetcially ?) so that it show the files/directories in the correct order. The below is what came up with, maybe of use to you or Fou-Lu - or it might just be useless altogether :).


function list_directory($dir,$_file) {
$list = array();
$stack[] = $dir;
$spacer = '&nbsp;';
while ($stack) {
$spacerCount = count($stack) - 1;
$current_dir = array_pop($stack);
if ($dh = opendir($current_dir)) {
while (($file = readdir($dh)) !== false) {
if ($file !== '.' && $file !== '..') {
$current_file = "{$current_dir}/{$file}";
if (is_file($current_file)) {
$list[] = array('file'=>$file,'is_directory'=>false,'indent'=>$spacerCount);
} elseif (is_dir($current_file)) {
$list[] = array('file'=>$current_file,'is_directory'=>true,'indent'=>$spacerCount);
$stack[] = $current_file;
}
}
}
}
}

$option_list = array();
//sort($list);
for($i=0,$n=count($list);$i<$n;$i++)
$option_list[] = "<option value=\"{$list[$i]['file']}\"".(($list[$i]['is_directory'] === false) ? 'class="file" ' : ' ').(($list[$i]['file'] == $_file) ? ' SELECTED' : '').">".(str_repeat($spacer,$list[$i]['indent']))."{$list[$i]['file']}</option>";
return implode("\n",$option_list);
}

$dir = dirname($_SERVER['SCRIPT_FILENAME']);
$file = 'index.php';

$select = "<select name=\"search_this_file\">".list_directory($dir,$file)."</select>";

echo $select;

dumpfi
06-05-2005, 05:57 PM
Have fixed some things in my script:

<?php
define('ROOT_DIRECTORY', realpath('HTTP Request'));
function printFileSelection($relDir) {
$absDir = realpath(ROOT_DIRECTORY.'/'.$relDir);
$file = basename($absDir);
echo '<select name="search_this_file">';
// don't let the user go closer to the root than ROOT_DIRECTORY
if(strpos(ROOT_DIRECTORY, $absDir) !== FALSE || !$absDir) $absDir = ROOT_DIRECTORY;
if(!is_dir($absDir)) $absDir = dirname($absDir);
// renew the relative path
$relDir = str_replace('\\', '/', substr($absDir, strlen(ROOT_DIRECTORY))).'/';
// let the user go "up" if he's not at the ROOT_DIRECTORY
$dir = dir($absDir);
if($absDir != ROOT_DIRECTORY) echo '<option value="',$relDir,'..">Go Up</option>';
// show the files
while(($entry = $dir->read()) !== FALSE) {
if($entry == '.' || $entry == '..') continue;
echo $absDir,' == ',$dir->path.'\\'.$entry;
echo '<option value="',$relDir,$entry,'" class="file"',($file == $entry) ? ' selected' : '','>',$entry,(is_dir($absDir.'/'.$entry)) ? ' -->' : '','</option>';
}
$dir->close();
echo '</select>';
}
echo '<form action="',getenv('SCRIPT_NAME'),'" method="get">';
$relDir = (isset($_GET['search_this_file'])) ? $_GET['search_this_file'] : '';
printFileSelection($relDir);
echo '<input type="submit" value="Open"></form>';
?>
dumpfi

mtd
06-05-2005, 07:40 PM
devosc: thanks for the input. Ideally, i would like to order the list with folders first, then files (not sure how). It is ordered alphebetically right now by default.

dumpfi: thanks, that fixed the second issue, but the defined root is still not working...

define('ROOT_DIRECTORY', realpath('HTTP Request')); returned an error (Fatal error: Call to undefined function: realpath() in /var/www/html/mtd/functions.php on line 8). Why HTTP Request and not just something like var/www/html/mtd/ ? That is where I want the Go Up to be capped off.

I changed it to
define('ROOT_DIRECTORY', realpath('var/www/html/mtd/'));and the error was gone, but it is still defaulting to the server root (where I have to open up var/www/html/mtd/ via the form to get where I want to be.) FYI, I echoed the values of $absDir and $relDir like this:
$dir->close();
echo '</select>';
echo "<b>absDir = </b>".$absDir."<br>";
echo "<b>relDir = </b>".$relDir."<br>";and they are always the same value, except $relDir has an added slash at the end (i.e. /home and /home/ ) Not sure if they are supposed to be equal, but it struck me as kind of odd that they mirrored each otheralmost exactly...

Anyway, let me know what you think of this. Is it something i'm doing wrong?

devosc
06-05-2005, 08:17 PM
Sorry, haven't been able to follow through what you've done. But try this (its not quite perfect --- haven't thourghly verified it, but looks reasonable, apart form the files in the root directory....).


function list_directory($dir,$_file) {
$list = array();
$stack[] = $dir;
$spacer = '&nbsp;';
while ($stack) {
$current_dir = array_pop($stack);
if ($dh = opendir($current_dir)) {
while (($file = readdir($dh)) !== false) {
if ($file !== '.' && $file !== '..') {
$current_file = "{$current_dir}/{$file}";
if (is_file($current_file)) {
$list[] = array('name'=>$file, 'file'=>$current_file,'is_directory'=>false);
} elseif (is_dir($current_file)) {
$stack[] = $current_file;
$list[] = array('name'=>basename($current_dir),'file'=>$current_file,'is_directory'=>true);
}
}
}
}
}

$cmp = create_function('$a,$b','return strcmp( $a[\'file\'], $b[\'file\']);');
usort($list,$cmp);
$option_list = array();
$_spacer = 0;
for($i=0,$n=count($list);$i<$n;$i++) {
if($i>0 && $list[$i-1]['is_directory'])
++$_spacer;
$option_list[] = "<option value=\"{$list[$i]['file']}\"".(($list[$i]['is_directory'] === false) ? 'class="file" ' : ' ').(($list[$i]['name'] == $_file) ? ' SELECTED' : '').">".(str_repeat($spacer,$_spacer))."{$list[$i]['name']}</option>";
}
return implode("\n",$option_list);
}

$dir = dirname($_SERVER['SCRIPT_FILENAME']);
$file = 'index.php';

$select = "<select name=\"search_this_file\">".list_directory($dir,$file)."</select>";

echo "<style type=\"text/css\">.file {font-style: italic;}</style>\n".$select;

devosc
06-05-2005, 09:44 PM
K, I think this is it, tested and fixed a couple of things from my last post:


function list_directory($dir,$_file) {
$list = array();
$stack[] = $dir;
$spacer = '&nbsp;&nbsp;';
while ($stack) {
$current_dir = array_pop($stack);
if ($dh = opendir($current_dir)) {
while (($file = readdir($dh)) !== false) {
if ($file !== '.' && $file !== '..') {
$current_file = "{$current_dir}/{$file}";
if (is_file($current_file)) {
$list[] = array('name'=>$file, 'file'=>$current_file,'is_directory'=>false);
} elseif (is_dir($current_file)) {
$stack[] = $current_file;
$list[] = array('name'=>end(explode('/',$current_file)),'file'=>$current_file,'is_directory'=>true);
}
}
}
}
}

$cmp = create_function('$a,$b','return strcmp( $a[\'file\'], $b[\'file\']);');
usort($list,$cmp);
$option_list = array();
$_spacer_offset = count(explode('/',$dir));
for($i=0,$n=count($list);$i<$n;$i++) {
$option_list[] = "<option value=\"{$list[$i]['file']}\"".(($list[$i]['is_directory'] === false) ? 'class="file" ' : 'class="folder" ').(($list[$i]['file'] == $_file) ? ' SELECTED' : '').">".(str_repeat($spacer,(count(explode('/',$list[$i]['file'])) - $_spacer_offset)))."{$list[$i]['name']}</option>";
}
return implode("\n",$option_list);
}

$dir = dirname($_SERVER['SCRIPT_FILENAME']);
$file = $dir.'/'.basename($_SERVER['SCRIPT_FILENAME']);
$select = "<select name=\"search_this_file\">".list_directory($dir,$file)."</select>";
echo "<style type=\"text/css\">.file {font-style: italic;} .folder{font-weight: bold;}</style>\n".$select;

mtd
06-06-2005, 01:50 AM
dumpfi and devosc, thanks to your help and input I am almost there! (devosc, your solution wasn't quite what I was looking for - listed the entire tree at once - but the code helped me fix a few things in my existing script)

Here's the updated code:
// DEFINE FILE TO SEARCH
if(is_file($search_this_file)) {
$string_in = file_get_contents($search_this_file);
}

// DEFINE ROOT DIRECTORY
define('ROOT_DIRECTORY', '/var/www/html/mtd');

// BUILD FILE SELECTION MENU
function buildFileSelection($relDir) {
$absDir = ROOT_DIRECTORY.$relDir;
$file = basename($absDir);
echo '<select name="search_this_file">';
// don't let the user go closer to the root than ROOT_DIRECTORY
if(strpos(ROOT_DIRECTORY, $absDir) !== FALSE || !$absDir) $absDir = ROOT_DIRECTORY;
if(!is_dir($absDir)) $absDir = dirname($absDir);
// renew the relative path
$relDir = str_replace('\\', '/', substr($absDir, strlen(ROOT_DIRECTORY))).'/';
// let the user go "up" if he's not at the ROOT_DIRECTORY
$dir = dir($absDir);
if($absDir != ROOT_DIRECTORY) {
echo '<option value="',$relDir,'..">Go Up</option><option>- - - - - - - - -</option>';
}
// show the files
while(($entry = $dir->read()) !== FALSE) {
if($entry == '.' || $entry == '..') continue;
echo $absDir,' == ',$dir->path.'\\'.$entry;
if(is_dir($absDir.'/'.$entry)) {
echo '<option value="',$relDir,$entry,'" class="folder"',($file == $entry) ? ' selected' : '','>',strtoupper($entry),' -->','</option>';
}
if(is_file($absDir.'/'.$entry)) {
echo '<option value="',$relDir,$entry,'" class="file"',($file == $entry) ? ' selected' : '','>',(is_file($absDir.'/'.$entry)) ? '' : '',$entry,'</option>';
}
}
$dir->close();
echo '</select>';
echo "<b>absDir = </b>".$absDir."<br>";
echo "<b>relDir = </b>".$relDir."<br>";
}

// PRINT FILE SELECTION MENU
function printFileSelection() {
echo '<form action="',getenv('SCRIPT_NAME'),'" method="get">';
$relDir = (isset($_GET['search_this_file'])) ? $_GET['search_this_file'] : '';
buildFileSelection($relDir);
echo '<input type="submit" value="Open"></form>';
}I had to remove the realpath()'s because for somereason that wasn't working, and I customized a few things (made the folders capitalized with strtoupper(), added/removed a '/' here and there) Overall, it is exactly where I need it, except...

Last (small) problem - the if($absDir != ROOT_DIRECTORY) { ... } statement works when you first access the script - the Go Up option is not displayed when the ROOT_DIRECTORY is reached. However, once you go into a folder and back out, the Go Up option appears in the ROOT_DIRECTORY. I know why this is happening, based on the following steps:

1) View selectbox for 1st time, open folder is "/var/www/html/mtd"
absDir = /var/www/html/mtd
relDir = /

2) Open folder "FOLDER1", Go Up option appears
absDir = /var/www/html/mtd/folder1
relDir = /folder1/

3) Use Go Up option in FOLDER1 to go back to root directory, Go Up option appears in ROOT_DIRECTORY
absDir = /var/www/html/mtd/folder1/..
relDir = /folder1/../

Now, the problem lies in the last step. In order for the if($absDir != ROOT_DIRECTORY) { ... } statement to work, absDir would have to become the original "/var/www/html/mtd", not "/var/www/html/mtd/folder1/.." Obviously, both work out to mean the same thing, but you can see why it needs to be remedied. I tried using a str_replace() but it didn't work (likely because I did something wrong, in typical 'me' fashion!)

Any ideas on how to remedy this (last forseeable) issue??

devosc
06-06-2005, 02:37 AM
If I understand right..

echo '<option value="',substr(realpath($absDir.'/../'),strlen(ROOT_DIRECTORY)),'"> Go Up</option><option>- - - - - - - - -</option>';

btw,

//$stack[] = $current_file;
would of not read the entire tree.

mtd
06-06-2005, 03:02 AM
Thanks devosc, you saved the day! That is sort of what I had attempted, but I was putting it in the wrong spot :-(

All I meant about displaying the entire tree was that when I opened the code, the text box displayed the whole tree at once like:

folder

folder2

file1.htm

folder3

file9.htm

file8.php
etc...

Maybe I misunderstood some part of the code? Anyway, everything works now thanks to you and dumpfi. THANKS SOOOOO MUCH!!!

mtd
06-12-2005, 03:28 AM
I'm back!

devosc, I have found a use for the code you provided in this post (06-05-2005 12:44 PM). However, I need to make it return a value ONLY if the selection is a file. When I tried removing the $current_file from
elseif (is_dir($current_file)) {
$stack[] = $current_file;
$list[] = array('name'=>end(explode('/',$current_file)),'file'=>$current_file,'is_directory'=>true); I got an error saying that something had to be greater than zero....I can get the exact text if it helps. Anyway, you know the code better than i so I was wondering if you knew how to fix this?

dumpfi
06-12-2005, 08:57 AM
I have modified my script to work without realpath():
<?php
define('ROOT_DIRECTORY', '/var/www/html/mtd');
function printFileSelection($relDir) {
$relDir = remSymbolicLinks($relDir).'/';
$absDir = ROOT_DIRECTORY.(($relDir != '/') ? '/'.$relDir : '');
$file = basename($absDir);
echo '<select name="search_this_file">';
// don't let the user go closer to the root than ROOT_DIRECTORY
if(strpos(ROOT_DIRECTORY, $absDir) !== FALSE || !$absDir) $absDir = ROOT_DIRECTORY;
if(!is_dir($absDir)) $absDir = dirname($absDir);
// let the user go "up" if he's not at the ROOT_DIRECTORY
$dir = dir($absDir);
if($absDir != ROOT_DIRECTORY) echo '<option value="',$relDir,'.." class="updir">Go Up</option>';
// if a directory is selected show the the files
while(($entry = $dir->read()) !== FALSE) {
if($entry == '.' || $entry == '..') continue;
echo '<option value="',$relDir,$entry,'" class="',(is_dir($absDir.'/'.$entry)) ? 'dir' : 'file','"',($file == $entry) ? ' selected' : '','>',$entry,(is_dir($absDir.'/'.$entry)) ? ' -->' : '','</option>';
}
$dir->close();
echo '</select>';
}
function remSymbolicLinks($link) {
$exLink = explode('/', $link);
for($i = 0, $count = count($exLink); $i < $count; $i++) {
switch($exLink[$i]) {
case '..':
if($i) {
array_splice($exLink, $i - 1, 2);
$i -= 2;
$count -= 2;
break;
}
case '.':
case '':
array_splice($exLink, $i, 1);
$i--;
$count--;
}
}
return implode('/', $exLink);
}
echo '<form action="',getenv('SCRIPT_NAME'),'" method="get">';
$relDir = (isset($_GET['search_this_file'])) ? $_GET['search_this_file'] : '';
printFileSelection($relDir);
echo '<input type="submit" value="Open"></form>';
?>I hope this helps.

dumpfi

mtd
06-20-2005, 11:46 PM
using devosc's code (post #9), I need to list the file/folder ONLY if it is not listed as 'excluded'. I have the excluded files and folders listed like so:
// EXLUDE FOLDERS AND FILES?
$excludeFolders = array('cms','images','cgi_bin');
$excludeFiles = array('');, but I can't get it to work...

ideas?



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum