Page 1 of 2

Review of a File Manager

Posted: Tue Apr 14, 2009 4:28 pm
by silverspy18
I know there are probably dozens of file managers out there that are ten times better than this one, but this is the first practical PHP application I have written, and I wanted to get some criticism from the community in terms of practicality, as I have a long list of features I want to add but am wondering if it is even worthwhile continuing on this project, and get some pointers for improving future projects.

Any points of criticism, comments, suggestions, positive or negative or just a quick approval or disapproval would be greatly appreciated.

Thanks.

Here is a link to a demo that I set up:

http://noname.aband0ned.net/fmdemo/

Login for administrative rights is (just so you can see what the features are):
Username: admin
Password: password

Source code for the main index.php file:

Code: Select all

 
<?php session_start();
//Begin microtime timer
$microtime_0 = microtime();
 
//Include external class that holds application settings
include("./fm_assets/appconfig.php");
 
//Construct instance of class app_config
$app_config = new app_config;
 
//Declare initial variables
$dir_to_read = "./";
$ico_dir = "./fm_assets/ico/";
$date_format = "d-m-y g:i:s a";
 
//Null declarations
$str_to_echo = "";
$dir_files = array();
$file_ext = array();
$err_msgs = "";
$edit_str= "";
$dir_folders = array();
 
//Load application configuration
if (file_exists('./fm_assets/config.txt')) {
    $app_config = unserialize(base64_decode(file_get_contents('./fm_assets/config.txt')));
} else {
    echo("<b>Note: The required configuration file does not exist.</b>");
}
 
//Define hidden files and folders
$dir_to_hide = $app_config->dir_to_hide;
$ext_to_hide = $app_config->ext_to_hide;
 
//Define directory to read from configuration file
$dir_to_read = $app_config->dir_to_read;
 
//Check if login attempt was made, if so check credentials
if (isset($_REQUEST['cklogin'])) {
    if (in_array($_POST['user'], $app_config->users)) {
        if ($app_config->passwords[$_POST['user']] == $_POST['pass']) {
            $_SESSION['reguser'] = $_POST['user'];
        } else {
            $err_msgs .= "Incorrect username and password.";
            $_SESSION['reguser'] = 'public';
        }
    } else {
        $err_msgs .= "Incorrect username and password.";
        $_SESSION['reguser'] = 'public';
    }
}
 
//Check if logout request was made, if so kill session
if (isset($_REQUEST['logout'])) {session_unset();}
 
//Check if session variable that holds current login user name is set, if not set to public
if (!isset($_SESSION['reguser'])) {$_SESSION['reguser'] = 'public';}
 
//Get directory to read if provided in URL
if (isset($_REQUEST['dir'])) {$dir_to_read = $_REQUEST['dir'];}
 
//Check that the directory to be read has a / at the end, if not, put one there
if (substr($dir_to_read, -1) != "/") {$dir_to_read .= "/";}
 
//Check if there was a request to create a new directory, if so create it
if (isset($_REQUEST['newdir'])) {
    if (!is_dir($_REQUEST['dir'].$_REQUEST['newdir'])) {
        mkdir($_REQUEST['dir'].$_REQUEST['newdir'], 0777) or die("The folder could not be created. Make sure write permissions are enabled.");
    } else {
        $err_msgs .= "<b>The named folder already exists. Please specify a new name.</b>";
    }
}
 
//Function to loop through a directory and delete all of its contents
function del_dir($directory) {
    $del_handler = opendir($directory);
    while (false !== ($del_readout = readdir($del_handler))) {
        if (is_dir($directory.'/'.$del_readout)) {
            if ($del_readout != "." && $del_readout != "..") {
                del_dir($directory.'/'.$del_readout);
            }
        } else {
            @unlink($directory.'/'.$del_readout);
        }
    }
    closedir($del_handler);
    @rmdir($directory);
}
 
//Check if there was a request to delete an object, if so delete it
if (isset($_REQUEST['delete'])) {
    if ($_REQUEST['objtype'] == 'file') {
        @unlink($_REQUEST['delete']) or die('The file could not be deleted. Make sure write permissions are enabled for the file, and that is is not currently in use. &nbsp;<a href="index.php">Return</a>');
    } elseif ($_REQUEST['objtype'] == 'folder') {
        if ($app_config->del_dir_contents == 'true') {
            del_dir($_REQUEST['delete']);
        } else {
        @rmdir($_REQUEST['delete']) or die('The folder could not be deleted. Make sure that the folder is not in use and is empty. The administrator may have disabled the capability to automatically delete the contents of a folder. If this is so, you must delete the contents manually. &nbsp;<a href="index.php">Return</a>');
        }
    }
}
 
//Check if there was a request to rename an object, if so rename it
if (isset($_REQUEST['rename'])) {
    if (!file_exists($_REQUEST['newname'])) {
        @rename($_REQUEST['rename'], $_REQUEST['newname']) or die('The file or folder could not be renamed. Make sure write permissions are enabled, and that it is not currently in use. &nbsp;<a href="index.php">Return</a>');
    } else {
        $err_msgs .= "<b>The named file already exists. Please specify a new name.</b>";
    }
}
 
 
//Check if we have permissions to access the directory
if (in_array($dir_to_read ,$app_config->access[$_SESSION['reguser']])) {$str_to_echo .= '<br /><b>You do not have permission to access this directory. </b><br /><br /><img src="./fm_assets/appico/parent.gif" alt="" />&nbsp;<a href="'.$_SERVER['PHP_SELF'].'?dir='.dirname($dir_to_read).'">Parent directory</a><br />';} else {
 
//See if the directory we are trying to view exists, if not print an error message and terminate the script
if (!is_dir($dir_to_read)) {$str_to_echo .= '<br /><b>The directory you are trying to view does not exist.</b><br /><br /><img src="./fm_assets/appico/parent.gif" alt="" />&nbsp;<a href="'.$_SERVER['PHP_SELF'].'?dir='.dirname($dir_to_read).'">Parent directory</a><br />';} else {
    
//Assign a handler to the directory to be read
$dir_handler = opendir($dir_to_read);
 
//Read the contents of each directory and put files in one array and folders in another
while (false !== ($file_readout = readdir($dir_handler))) {
    if (is_dir($dir_to_read.$file_readout)) {
        if ($app_config->hide_denied_folders == 'true') {
            if (!in_array($file_readout, $dir_to_hide) && !in_array($dir_to_read.$file_readout.'/' ,$app_config->access[$_SESSION['reguser']])) {
                $dir_folders[] = $file_readout;
            }
        } else {
            if (!in_array($file_readout, $dir_to_hide)) {
                $dir_folders[] = $file_readout;
            }
        }
    } else {
        $delimiter_pos = strpos($file_readout, ".");
        if (!in_array(ltrim(substr($file_readout, $delimiter_pos), "."), $ext_to_hide) && !in_array($file_readout, $dir_to_hide)) {
            $dir_files[] = $file_readout;
        }
    }
}
 
 
//Check to see that the directory is not empty, if it is, print an error message and terminate
if (count($dir_folders) + count($dir_files) == 0) {$str_to_echo .= '<br /><b>The directory you are trying to view is empty.</b><br /><br /><img src="./fm_assets/appico/parent.gif" alt="" />&nbsp;<a href="'.$_SERVER['PHP_SELF'].'?dir='.dirname($dir_to_read).'">Parent directory</a><br />';} else {
 
 
// Get properties for each folder and assign values to an array
foreach ($dir_folders as $_dir_folders) {
    
    //Get date modified for each folder
    $folder_modified[] = date($date_format, filemtime($dir_to_read.$_dir_folders));
}
 
// Get properties for each file and assign values to an array
foreach ($dir_files as $_dir_files) {
    // Get file extension for each file, if directory mark with 'DIR'
    $delimiter_pos = strpos($_dir_files, ".");
    if (false !== $delimiter_pos) {
        if (!in_array(ltrim(substr($_dir_files, $delimiter_pos), "."), $ext_to_hide)) {
            $file_ext[] = ltrim(substr($_dir_files, $delimiter_pos), ".");
        }
    } else {
        $file_ext[] = "";
    }
    
    //Get file size for each file
    $file_size_bytes = filesize($dir_to_read.$_dir_files);
    if ($file_size_bytes < 1024) {$file_size[] = $file_size_bytes." bytes";}
    elseif ($file_size_bytes < 1048576) {$file_size[] = round($file_size_bytes/1024, 3)." KB";}
    else {$file_size[] = round($file_size_bytes/104856, 3)." MB";}
    
    //Get date modified for each file
    $file_modified[] = date($date_format, filemtime($dir_to_read.$_dir_files));
}
 
//Eliminate any unwanted entries in list of file extensions
if (is_array($file_ext)) {$file_ext_fresult = array_diff($file_ext, $dir_to_hide);}
 
//Get the key of the first element of each array, first we need to reset them to their first element
 
 
//Write out the directory we are viewing
$str_to_echo .= '<p>Directory: '.$dir_to_read.'</p>';
 
//Write table
$str_to_echo .= '<table cellspacing="0px" width="100%">'."\n";
$str_to_echo .= '<tr class="header"><th><b>Ext</b></th><th><b>Filename</b></th><th><b>Size</b></th><th><b>Modified</b></th><th><b>Edit</b></th></tr>';
 
//If the read directory is not the root directory add a parent 
if ($dir_to_read != "./") {
    $str_to_echo .= '<tr class="even"><td><img src="./fm_assets/appico/parent.gif" alt="" /></td><td><a href="'.$_SERVER['PHP_SELF'].'?dir='.dirname($dir_to_read).'">Parent directory</a></td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>';
}
              
//Check if option for deleting all contents of a folder automatically is true for use in delete prompt
if ($app_config->del_dir_contents == 'true') {$all_contents = ' and all of its contents';} else {$all_contents = '';}
 
//Write folder names and properties
foreach ($dir_folders as $key=>$value) {
    if ($key%2 == 1) {$bgcolorclass = "even";} else {$bgcolorclass = "odd";}
    if ($app_config->viewindex == 'true') {
    if (file_exists('./'.$dir_folders[$key]."/index.php")) {$view_index_link = '&nbsp;&nbsp;&nbsp;<a class="viewindex" href="'.$dir_to_read.$dir_folders[$key].'/index.php">View index</a>';} elseif (file_exists($dir_folders[$key]."/index.html")) {$view_index_link = '&nbsp;&nbsp;&nbsp;<a class="viewindex" href="'.$dir_to_read.$dir_folders[$key].'/index.html">View index</a>';} else {$view_index_link = "";} } else {$view_index_link = "";}
 
if (in_array($dir_to_read, $app_config->write[$_SESSION['reguser']]) || $app_config->permissions[$_SESSION['reguser']] == 'admin') {$edit_str = '<img class="smbttn" src="./fm_assets/appico/delete.gif" alt="Delete" onclick="confirm_delete(\''.$dir_to_read.$dir_folders[$key].'\',\'folder\',\''.$dir_to_read.'\',\''.$all_contents.'\')" />&nbsp;<img class="smbttn" src="./fm_assets/appico/edit.gif" alt="Rename" onclick="prompt_rename(\''.$dir_to_read.$dir_folders[$key].'\',\''.$dir_to_read.'\')" />';}
 
    $str_to_echo .= '<tr class="'.$bgcolorclass.'"><td><img src="'.$ico_dir.'dir.png" alt="dir" /></td><td><a href="index.php?dir='.$dir_to_read.$dir_folders[$key].'">'.$dir_folders[$key].'</a>'.$view_index_link.'</td><td>&nbsp;</td><td>'.$folder_modified[$key].'</td><td>'.$edit_str.'</td></tr>'."\n";
}
 
//Write file names and properties
if (count($dir_folders)%2 == 1) {$modeq = 0;} else {$modeq = 1;}
foreach ($dir_files as $key=>$value) {
    if ($key%2 == $modeq) {$bgcolorclass = "even";} else {$bgcolorclass = "odd";}
    if (in_array($dir_to_read, $app_config->write[$_SESSION['reguser']]) || $app_config->permissions[$_SESSION['reguser']] == 'admin') {$edit_str = '<img class="smbttn" src="./fm_assets/appico/delete.gif" alt="Delete" onclick="confirm_delete(\''.$dir_to_read.$dir_files[$key].'\',\'file\',\''.$dir_to_read.'\',\'\')" />&nbsp;<img class="smbttn" src="./fm_assets/appico/edit.gif" alt="Rename" onclick="prompt_rename(\''.$dir_to_read.$dir_files[$key].'\',\''.$dir_to_read.'\')" />';}
    if (file_exists($ico_dir.$file_ext[$key].'.png') == true) {$ico_file = $ico_dir.$file_ext[$key].'.png';} else {$ico_file = $ico_dir.'unknown.png';}
    $str_to_echo .= '<tr class="'.$bgcolorclass.'"><td>'.'<img src="'.$ico_file.'" alt="'.$file_ext[$key].'"/>'.'</td><td><a href="'.$dir_to_read.$dir_files[$key].'">'.$dir_files[$key].'</a></td><td>'.$file_size[$key].'</td><td>'.$file_modified[$key].'</td><td>'.$edit_str.'</td></tr>'."\n";
}
 
$str_to_echo .= '</table>'."\n";
 
} //Bracket ends if statement on line 32
} //Bracket ends if statement on line 17
} //Bracket ends if statement on line 61
 
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Viewing <?php echo($dir_to_read); ?></title>
<style type="text/css">
body {
    font-family:Myriad Pro, Arial, Helvetica, sans-serif;
    color:#CCC;
    background-color:#000;
    font-size:12px;
}
 
a:link {
    color: #CCC;
}
 
a:visited {
    color: #CCC;
}
 
.divheading {
    background-color:#333;
    width:auto;
    height:30px;
    background-image:url(fm_assets/img/loginbar.png);
    background-repeat:repeat-x;
}
 
.even {
    background-color:#333;
    text-align:left;
}
 
.odd {
    background-color:#666;
    text-align:left;
}
 
.header {
    background-color:#000;  
    text-align:left;
}
 
 
.maincontainer {
    padding:10px;
}
 
form.login {
    float:right;
}
 
img.logout {
    float:right;
}
 
input.login {
    width:75px;
    height:12px;
    font-size:10px;
}
 
p.error {
    font-weight:bold;
    color:#F00;
}
 
a.viewindex {
    font-size:10px;
    padding-left:4px;
}
 
img.smbttn {
    cursor:pointer;         
}
 
div.footer {
    font-size:10px;
    text-align:center;
}
</style>
<script type="text/javascript">
<!--
function confirm_delete(filename, objtype, dir_to_read, allcontents) {
    winconfirm = confirm('Are you sure you want to delete the '+objtype+' \''+filename+'\''+allcontents+'?');
        if (winconfirm) {
            window.location = 'index.php?delete='+filename+'&objtype='+objtype+'&dir='+dir_to_read;
        }
}
 
function prompt_rename(filename, dir_to_read) {
    winprompt = prompt('Enter a new name and/or location for \''+filename+'\'.',filename);
        if (winprompt != null) {
            window.location = 'index.php?rename='+filename+'&newname='+winprompt+'&dir='+dir_to_read;
        }
}
 
function prompt_newdir(dir_to_read) {
    winprompt = prompt('Enter the name for the new directory','New Folder');
        if (winprompt != null) {
            window.location = 'index.php?newdir='+winprompt+'&dir='+dir_to_read;
        }
}
//-->
</script>
</head>
 
<body>
<div class="maincontainer"><div class="divheading">
<?php 
if ($_SESSION['reguser'] == 'public') {
    echo('<form class="login" action="index.php?cklogin=true" method="post" name="login"><img src="fm_assets/img/username.png" alt="User:" align="absmiddle" /><input class="login" type="text" name="user" /><img src="fm_assets/img/password.png" alt="Pass:" align="absmiddle" /><input class="login" type="password" name="pass" /><input type="image" id="loginbtn" src="./fm_assets/img/loginbtn_idle.png" align="absmiddle"/>
</form>');
} else {
    echo('<form class="login" action="index.php?logout=true" method="post" name="login">Welcome <b>'.$_SESSION['reguser'].'</b>.<input type="image" id="loginbtn" src="./fm_assets/img/logoutbtn_idle.png" class="logout" align="absmiddle" border="0px"/></form>');    
}
?>
<a href="index.php"><img src="fm_assets/img/logo.png" alt="File Manager" border="0px" align="absmiddle" /></a></div>
<div class="divheading" style="height:20px; background-image:url(fm_assets/img/optionsbar.png);"><a href="index.php?dir=<?php echo($dir_to_read); ?>"><img src="fm_assets/img/refresh_dir.png" alt="Refresh" border="0px" /></a><?php if ($app_config->upload[$_SESSION['reguser']] == 'true'){echo('<a href="fm_assets/upload.php?dir='.$dir_to_read.'"><img src="fm_assets/img/upload_file.png" alt="Upload file" border="0px" /></a>');} if (in_array($dir_to_read, $app_config->write[$_SESSION['reguser']]) || $app_config->permissions[$_SESSION['reguser']] == 'admin') {echo('<img class="smbttn" src="./fm_assets/img/newdirectory.png" alt="New directory" onclick="prompt_newdir(\''.$dir_to_read.'\')" />');} if (isset($_SESSION['reguser'])) { if ($app_config->permissions[$_SESSION['reguser']] == 'admin') {echo('<a href="./fm_assets/adminset.php"><img src="fm_assets/img/adminsettings_btn.png" border="0px"/></a>');}} ?></div>
 
<?php echo('<p class="error">'.$err_msgs.'</p>'); echo($str_to_echo);?><div class="footer"><?php echo('<br />Generated in '.round((microtime() - $microtime_0), 4).' seconds.'); ?> &bull; Copyright &copy 2008 Andrew Loheac, Bluworks</div></div>
</body>
</html>
 

Re: Review of a File Manager

Posted: Tue Apr 14, 2009 9:41 pm
by it2051229
yeah the index.php of WAMP or XAMPP or LAMP itself is already a file manager which is similar to yours.... You know you can break that click and refresh page using AJAX to make it better and also provide windowing which can be done using javascript so that users can open multiple folders at a time.

Re: Review of a File Manager

Posted: Tue Apr 14, 2009 9:59 pm
by silverspy18
Yeah, I've been thinking about using AJAX for a little while, but it just seems like such a daunting task to try to implement it, especially since I've never used much of it before. Would the advantages really be worth the work?

Re: Review of a File Manager

Posted: Tue Apr 14, 2009 11:52 pm
by max529
silverspy18 wrote:Yeah, I've been thinking about using AJAX for a little while, but it just seems like such a daunting task to try to implement it, especially since I've never used much of it before. Would the advantages really be worth the work?
Depends on how you use it,and use Jquery libirary if you plan to implement ajax.One area you might want to use ajax is to check if the contents of the directory currently displayed has been modiied,and reload the page if it has been.

Re: Review of a File Manager

Posted: Wed Apr 15, 2009 2:27 am
by it2051229
yup... it's worth the work

Re: Review of a File Manager

Posted: Wed Apr 15, 2009 10:04 am
by pickle
Make sure you hide index.php - I renamed it to index2.php & broke the app (I changed it back).

I'd also restrict the uploading of PHP files - I was able to upload a PHP file that had phpinfo() in it. I'm sure others could come up with some more malicious files to upload.

If you don't use AJAX - at least redirect users after an action is done. After I deleted a file, I reloaded the page & got an error - as the $_GET variables were telling your app to delete a file that doesn't exist. Redirecting the user after an action is done will eliminate users trying to do the same action twice.

You should disable the 'Remove' functionality for the admin user.

Seems pretty straightforward. Other than those few gaping security holes - not bad.

Re: Review of a File Manager

Posted: Wed Apr 15, 2009 7:28 pm
by silverspy18
Thanks for the input all, I guess I'm going to learn AJAX now

Re: Review of a File Manager

Posted: Wed Apr 15, 2009 11:42 pm
by alex.barylski
I did as pickle and renamed index.php to index.txt and it broke the script -- sorry my bad. Not sure how pickle fixed that?

I wouldn't just hide that file but make it inaccesible from the file manager. Also you need to probably employ some kind of check to prevent browsing outside or inside directories you do not wish to expose (outside docroot, inside some private directory, etc).

I have a similar file manager I developed for a crude CMS here:

http://www.sourceforge.net/projects/texocms

Might be useful, who knows...have fun and good job...again sorry for breaking your script. :oops:

Re: Review of a File Manager

Posted: Thu Apr 16, 2009 9:22 am
by silverspy18
Thanks for taking a look at it PCSpectra. I just renamed it over ftp, but it is something that I do have to fix. (Check if index.php is under directory './', if so, hide it?)

How could I check the location of the directory currently being viewed relative to the location of index.php (essentially the root directory, './')? How do I prevent user from changing $_GET['dir'] in the URL to a parent directory of that 'root' folder (i.e. dir=../)? I was thinking about just checking if the first two characters are periods, but somebody could go to a sub directory first, and then go backwards (dir=./Pictures/../..).

Thanks for all your help.

Re: Review of a File Manager

Posted: Thu Apr 16, 2009 9:47 am
by pickle
I made sure to rename index.php to another php file, so I could access it.

In my filemanagers, I do a check on the equivalent of $_GET['dir'], to make sure it's a child of the directory I want it to be.

Something like (untested):

Code: Select all

$fs_dir = dirname(__FILE__).$_GET['dir'];
if(strpos(dirname(__FILE__),realpath($fs_dir)) === 0)
   //user is viewing an OK directory
Basically it just checks that the directory the user requested is below the directory the script is running from.

Re: Review of a File Manager

Posted: Thu Apr 16, 2009 8:37 pm
by silverspy18
Thanks for the tip pickle, but I can't seem to get it to work. Just as a test, I stuck this in at line 38 (refer to code on first post):

Code: Select all

 
$fs_dir = dirname(__FILE__).$dir_to_read;
 if(strpos(dirname(__FILE__),realpath($fs_dir)) === 0) {echo('Directory OK');}
 
No matter what the directory is, 'Directory OK' is always printed at the top of the page. I tried bypassing the variable with $dir_to_read $_GET['dir'] also, but got the same result. I set the directory to "./_notes/../../../../", "../../" and "./_notes/", again, all with the same result.

Re: Review of a File Manager

Posted: Fri Apr 17, 2009 9:50 am
by pickle
what do realpath($fs_dir) and dirname(__FILE__) look like?

Re: Review of a File Manager

Posted: Fri Apr 17, 2009 2:25 pm
by silverspy18
Here are the printouts of realpath($fs_dir) and dirname(__FILE__) under various directories:

Directory: './'
realpath($fs_dir): C:\Apache2.2\htdocs\filemgr
dirname(__FILE__): C:\Apache2.2\htdocs\filemgr

Directory '../'
realpath($fs_dir): C:\Apache2.2\htdocs\filemgr
dirname(__FILE__): C:\Apache2.2\htdocs\filemgr

Directory './_notes/../..'
realpath($fs_dir): C:\Apache2.2\htdocs\filemgr
dirname(__FILE__): C:\Apache2.2\htdocs\filemgr

I find that the results of those two functions are always the same directory: the location of index.php

I used this code to see what they are:

Code: Select all

 
$fs_dir = dirname(__FILE__).$dir_to_read;
 if(strpos(dirname(__FILE__),realpath($fs_dir)) === 0) {echo('Directory OK');}
 
 echo('realpath: '.realpath($fs_dir));
 echo('dirname: '. dirname(__FILE__));
 

Re: Review of a File Manager

Posted: Fri Apr 17, 2009 3:38 pm
by pickle
$dir_to_read should have the value of $_GET['dir'], or whatever the user entered directory is.

Re: Review of a File Manager

Posted: Sat Apr 18, 2009 9:43 am
by silverspy18
Oops.....It would have helped if I placed that code after $dir_to_read was set.....

Now I get different results:
Directory NOT OK
realpath: C:\Apache2.2\htdocs\filemgr\_notes
dirname: C:\Apache2.2\htdocs\filemgr
dir_to_read: ./_notes/
$_GET[DIR]: ./_notes

Directory OK
realpath: C:\Apache2.2\htdocs\filemgr
dirname: C:\Apache2.2\htdocs\filemgr
dir_to_read: ./
$_GET[DIR]: .

Directory OK
realpath: C:\Apache2.2\htdocs\filemgr
dirname: C:\Apache2.2\htdocs\filemgr
dir_to_read: ../
$_GET[DIR]: ../

I am getting the opposite effect I want...subdirectories that should be OK are being recognized as directories that the user shouldn't access, and vice vera. I would change '===' to '!==' in the if statement, but then the root directory './' is recognized as a directory that shouldn't be accessed. How could this issue be addressed?

Thanks