Pages

Wednesday, 4 May 2011

Task 2 - Building a Web Space Management System

Introduction

Welcome again, this week's blog post will tackle the second task that I will present for my Coursework. The task instructions are as follows:-

Write a remote Web space management system suitable for handling Web site content of various types. It should allow a user to add and organise files to a personal Web area which is secured by password. 

This program should include the following features.
  1. Your program should be written as PHP scripts. The user should be able to work with this program via a Web browser from any computer connected to the Internet.
  2. When your program starts, it should ask the user to enter a password and username, and not allow the user to access their Web space unless they know the password. Passwords should be stored in an appropriate MySQL database.
  3.  Once allowed access the user should be able to:
    1. Make and delete directories
    2. Delete files
    3. Upload new files
    4.  Only be able to access their own space, which should have space limits imposed upon it.

User data and passwords should be stored in an appropriate MySQL database or file system which the PHP script can access; you must consider security implications. There are no restrictions on the style of the user interface, although you should consider ease of use and design to be issues too.

The task also suggests adding additional features, some of which are encouraged. I did not do all the suggested functionality, but I did try some, and also added some features of my own.

A Little background

As I made a file upload website, I decided to give it an adequate name. EasyUpload is the only name I could come up with, its easy to remember and self descriptive. The idea behind EasyUpload is to provide an easy environment for a user to add and manage files in his web space. In this way his files are available from anywhere, without the need to carry any pen drives or external disks. Files can be uploaded and downloaded from any device that connects to the internet and uses a modern browser. The Theme is made of greyish and bluish colours and uses Linux Ubuntu look alike icons to create an easy to use and familiar environment.

The Web Site has a total of 8 files. It is mainly written in php, but also uses Javascript and CSS to obtain better visuals and functionality on the client side. For better code handling, some functions were put in separate files to avoid having too much code in the php pages handling the HTML code.

All styling is done from a single CSS file which applied visual colours and images to the HTML Code. Although all styling is done from a single file, some properties for a particular HTML tag, might have been slightly altered from internal page styles to better fit in the page.

The rest of the files are all php files. The Web page consists of three screens, a Login Screen, a Create New User screen and a Workspace. These screens use code which is inherited from other php files as well. A file call encrypt.php contains functions for encrypting passwords, while the file Functions.php contains basic functions that are mostly used in the Workspace Page. Another two separate php files are used, one for downloading, and another for uploading files. Most of the code used was already created and illustrated in my previous posts. I reused the login screen of last week's post, but I added CSS styling and some code to imporve security.

For storing login information, I used a MySql Database which contains a table called Login, that stores usernames and passwords. Again, more detailed descriptions are available in previous posts.

The Login Screen

Now that we are done with the background information, I will start explaining each screen starting with the Login. A already made a quite detailed blog entry last week, so I won't go over it again, I will just make a Quick summary.

The Login connects with a MySql Database to retrieve a user name and a password, given the user name as a search parameter. The Login are verified, and the user is stored in a session. The user has a remember me option that creates a cookie, that is allows the user to remain logged in even after the session ends. When a user enters the login screen and has this cookie enabled, the contents of the cookie are recopied to a session and the login is automated. Now last week I mentioned adding some security, which today, I did, but first lets take a look at the login screen.



The login is made up of a form of fixed width whcih is imposed on a background image. Besides the visuals, the  Login has a new link that allows you to create a new user. this Link directs you to a page which will be described later. Visuals are not the only thing improved. Lately I have read about a lot of site being attacked so I decided to enhance my security. The first thing I did was to protect my web site against SQL injection. All inputs that will be queried to the database are passed through the function mysql_real_escape_string(). This function adds escape sequences to characters such that might break the query. This function should render useless any attempt to execute a query written instead of the username.

Password encryption is also important in case passwords a stolen. For this task I create a php File Called Encrypt which contains a function that encrypts the password. I decided to use the crypt() function using the MD5 algorithm. The crypt function provides a one way only encryption which cannot be translated back to its original form. In my case it is good enough since I can crypt the entered passwords and compare them to the once stored in the database. To further improve security, I added a salt to the equation. The salt is a string that is added to the crypt function such that it outputs a different encryption result that renders, passwords discovery more difficult. MD5 encryption must have a salt that begins with $1$ an up to 9 other characters. To create a different salt for each user, I made a function that generates a salt from the username, by repeating letters from the username until all 12 characters for the encryption are filled. the function than crypts the file with the salt and removes the first 12 characters, which are the salt itself. The result is an encrypted password that should be take time to crack.

The function described about is called genPassword.  The function str_split, splits the username into an array of characters. A foreach loop, continues to add characters to the salt until it reaches a maximum size of nine characters. strlen() is used to Identify the character's Length. Then crypt($Psd,"\$1\$".$Salt) is used to create the MD5 encryption. substr() is used to truncate the first twelve characters of the encrypted password.

<?php
function genPassword($Usr,$Psd)
{
    $arr = str_split($Usr);
    $Salt="";
    for(; ;)
    {
        if ( strlen( $Salt) >= 9) break;
        foreach($arr as $value)
        {
            if ( strlen( $Salt) < 9)            {
            $Salt .= $value;            }
            else
            {
            break;

            }
        }

    }
    
    if (CRYPT_MD5==1)
    {
    return substr(crypt($Psd,"\$1\$".$Salt),12);    }
}
?>

The new User Screen

As the name implies the screen is used to register new users. The users are requested to enter a username, and a password. The password must be confirmed. In the case of a username that already exists, an error message is displayed. 

Appropriate error messages are displayed when any of the fields are left empty, or the password does not match the confirm password. When the login details are verified to be correct, the password is encrypted and a record is saved in the login table in a MySql Database.

It is good practice to make password policies when creating user passwords. For the purpose of this exercise I only did a policy to make passwords larger than 4 characters. I didn't do any strict policies, but it is something that must be applied if the website where to function in a real environment.

Once the user is created, the web page directs you into the login page. Note, no directories are created till this point. Directories are created the first time the user logs into the system. The code to create a new user is plain and simple, so I won't go into any more further details.


Web Space

After the User creates a Login and Logs in, his directory is created. More exactly, when a user login in, and his web space is not available, it is assumed that he has logged in for the first time, and his directory is created. When a user is logged to web space, the user login is verified again and finally he can start using his workspace. In case of any errors during the verification, the user is Logged out.


The code below shows how to check if a directory exists.
<?php
if (file_exists(getcwd()."\\Users\\".$_SESSION['User']."\\")==FALSE)
{
mkdir(getcwd()."\\Users\\".$_SESSION['User']);
}
?>

The function file_exists() checks whether a particular file or directory exists. getcwd() gets the current working directory where the php file is located. In this website the Web Space is the getcwd() plus the folder 'Users' plus the username. This directory is saved in a session when the user logs in. Setting the username as the folder name for the directory ensures that all directories are unique since all users have a unique username. If the directory does not exist, mkdir() is used to create it.

Displaying Files and Folders in the WorkSpace

To display the list of files in the working directory, I used a function that returns an array of the names of any files and folders in a particular directory. Well easier said than done. To do this function, I had to make some research, but fortunately, a lot of functions are available for php. I called the function getDirectoryList().

<?php
function getDirectoryList ($directory) 
  {

    // create an array to hold directory list
    $results = array();

    // create a handler for the directory
    $handler = opendir($directory);

    // open directory and walk through the filenames
    while ($file = readdir($handler)) {

      // if file isn't this directory or its parent, add it to the results
      if ($file != "." && $file != "..") {
        $results[] = $file;
      }

    }

    // tidy up: close the handler
    closedir($handler);

    // done!
    return $results;

  }
?>

The function takes $directory as the working directory. opendir() is used to creates a handler for the directory. readdir($handler) returns the file and folder names in the directory of the provided handler. In the code there is also an if statement that check that only the files in the directory are actually returned by the function. The final output of this function is an array containing all file names in a particular directory.

To display the files on the screen, I used HTML tables which are generated by the php script. The list of files and folders obtained by the getDirectoryList() function is used to create the table. the program loops through every name on the list. The names in the list are added to the working directory and checked using is_dir(). This function returns through in case the path is a directory. Each file or folder is inserted in a separate row in the HTML Table. Files have different code from Folder. This is why is_dir is important. Files have different class names and other differences in the code from folders. Class names help for styling while the other differences are needed because files behave differently than folders.

The following picture shows how files and folders are listed on this site:


Moving through directories

Earlier I said that files behave differently from folders. This is because up on click, files start to download. on the other hand folders cannot be downloaded, but you can navigate through folders and download it's contents. When you click on a folder, you navigate into it to see the list of files in it. You can also navigate back into the its parent folder.

File and folder names in the List are Hyper Links that  redirect the webpage, and pass a query string. In the case of folder theQuery String passed is DirName=$directoryName. Files will be explained later on. The code below shows what happens when a directory name is passed through a query string.

<?php
if (isset($_SESSION['DirName']))
{

    $MainDirectory = $_SESSION['DirName'];

    if (isset($_GET['DirName']))
    {
    if($_GET['DirName']!="" and $_GET['DirName']!=".." and $_GET['DirName']!=".")
      {
        $MainDirectory =$MainDirectory. $_GET['DirName'].'\\';
      }
     header('Location: '. $_SERVER['SCRIPT_NAME']);
    }

    if(file_exists($MainDirectory)) $_SESSION['DirName']=$MainDirectory;
    else 
   {
   $MainDirectory=$_SESSION['DirName'];
   echo "<div><script >alert('Directory does not Exist');</script></div>";
   }

}
else 
{
   $MainDirectory = getcwd().'\\Users\\'.$username.'\\';
   if($_GET['DirName']!="" and $_GET['DirName']!=".." and $_GET['DirName']!=".")
   {
      if($_GET['DirName']!="")
      {
       $MainDirectory =$MainDirectory. $_GET['DirName'].'\\';
      }
      header('Location: '. $_SERVER['SCRIPT_NAME']);
    }

    if(file_exists($MainDirectory)) $_SESSION['DirName']=$MainDirectory;
    else 
    {
    $MainDirectory=$_SESSION['DirName'];
    echo "<div><script >alert('Directory does not Exist');</script></div>";
    }
}
?>

The Session $_SESSION['DirName']   holds the current directory the user is in. If this session is set, the contents of the session are set as the current (main) directory. The program then checks if a query string was passed. If $_GET['DirName']  is set and is not empty, the contents are added to the current directory, meaning that the directory moved to a new folder. The existent of the folder is check using file_exists(). It the folder exists, the user is navigated to see it's contents, if the folder does not exist the user is given an error message and remains in the current folder. The new directory is always saved to $_SESSION['DirName']. In the case that the session containing the dirName, does not exist, the main directory is given the default directory path, at first. The same process is done to see if any string query is present, and if so the navigation to that folder occurs.  Notice the check $_GET['DirName']!=".."and $_GET['DirName']!=".".  This line verifies that DirName is not used to go up in the parent folder. This is because, if a user enters the query string manually and continues to move up through folders, he might end up in directories he should not be allowed to see.

The previous explanation shows you how to go down into folder navigation, but the user needs to be able to move back to the parent folders in a controlled way. I did not use the ".." in the path to move up through folders, instead I used a function called dirname().


<?php
if(isset($_POST['btnUp']))
 {
    if(dirname($MainDirectory)!=getcwd()."\\Users")    {
        $MainDirectory=dirname($MainDirectory).'\\';
        $_SESSION['DirName']=$MainDirectory;
    }
 }
?>


When the button called btnUp is pressed, the program checks if the parent of the directory is the folder called Users. The folder users is in the same directory of the php pages and contains all the user directories. If so, the user will not be allowed to navigate up, because he/she would be navigating out of his root folder. If this is not the case, the main directory is set as the current folder's parent and is save into the appropriate session.

Creating A new Directory

Well to create a new Directory, the user must Enter a directory name and press the New Folder button. The Code checks if a directory name is entered. The code then checks if the directory exists and if so it creates the session $_SESSION['Error']. This session is used to hold errors and are then displayed on page refresh. In this case it is needed as the page will be refreshed to remove the Get parameters from the address bar. If the new folder name does not exist, a new folder is created using mkdir(). This folder is listed in the files and folders list.

<?php
if(isset($_POST['btnNewDir']))
{
  if(isset($_POST['txtNewDir']) and $_POST['txtNewDir']!="" )
  {
     if( file_exists($MainDirectory.$_POST['txtNewDir']))
     {
         $_SESSION['Error'] ="Directory already Exists";
     }
     else
     {
     mkdir($MainDirectory.$_POST['txtNewDir']);
     }
  }
  header('Location: '. $_SERVER['SCRIPT_NAME']);
}
?>

The following image shows the new folder button, and the text box to enter the new directory name.



Download File

There is no use of uploading files if you cannot download them later. EasyUpload allows you to download the files listed in the directory. Downloads are handled by the script Download.php. When the user clicks on a file name he is redirected to Download.php in a link similar to this:-

Download.php?FileName=Hello.jpg

Download.php verifies the user again, and obtains the path of the file to be downloaded from the session  $_SESSION['DirName']. Having the file path, the following code is executed to allow user to download the file.


<?php
if(isset($_GET['FileName']))
{
$fullPath = $MainDirectory.$_GET['FileName'];
//echo $fullPath;
 if ($fd = fopen ($fullPath, "r")) {
    $fsize = filesize($fullPath);
    $path_parts = pathinfo($fullPath);
    
    if(isset($path_parts["extension"]))
    {
    $ext = strtolower($path_parts["extension"]);
    }
    else
    {
    $ext="";
    }
    
    switch ($ext) {
        case "pdf":
        $mime_type ="application/pdf";
         break;

         case "txt":
        $mime_type ="force-download";
         break;
// More Case Statements here
       
       default:
        $mime_type="application/force-download";
       break;
    }
     header("Content-type: ".$mime_type);
        header("Content-Disposition: attachment; filename=\"".$path_parts["basename"]."\"");
        header("Content-Transfer-Encoding: binary");
        header("Accept-Ranges: bytes");

    header("Content-length: $fsize");
    header("Cache-control: private"); //use this to open files directly
    while(!feof($fd)) {
        $buffer = fread($fd, 2048);
        echo $buffer;
    }
}
fclose ($fd);
//exit;
 
 }
?>

The function fopen() opens the file given its full path. pathinfo() returns an array with path information. The file's extension is obtained from the array and depending on the extension, the mime type of the file is identified. Using the header() function several download settings are added. Finally the file is read into a buffer, and the buffer is echoed using the echo() method. The result is a file download in a browser. Download is forced and the files cannot be viewed on the Web Space.

The image below shows how the file Water lil.jpg can be Downloaded.



Upload File

The most important thing of a file uploading web site, is of course the Upload. The upload occurs on a separate form, which posts the data to another page called Upload.php. The server is limited to a maximum of  5MB, meaning that any file greater than that size will be immediately discarded. The workspace is also limited to 5MB and when that file size is exceeded, the file is discarded and an error message is displayed. The web Space allows uploading of any file type. Does not supported by the download, will have force-download as a mime type. Like the Download.php page, the user is verified before the upload starts occuring. The folowing code shows the file  upload.

Getting the directory Size:-

<?php
function getDirectorySize($path) 
{ 
  $totalsize = 0; 
  $totalcount = 0; 
  $dircount = 0; 
  if ($handle = opendir ($path)) 
  { 
    while (false !== ($file = readdir($handle))) 
    { 
      $nextpath = $path . '/' . $file; 
      if ($file != '.' && $file != '..' && !is_link ($nextpath)) 
      { 
        if (is_dir ($nextpath)) 
        { 
          $dircount++; 
          $result = getDirectorySize($nextpath); 
          $totalsize += $result['size']; 
          $totalcount += $result['count']; 
          $dircount += $result['dircount']; 
        } 
        elseif (is_file ($nextpath)) 
        { 
          $totalsize += filesize ($nextpath); 
          $totalcount++; 
        } 
      } 
    }
   closedir($handle);
  }
$total['size'] = $totalsize;
$total['count'] = $totalcount; 
$total['dircount'] = $dircount;
return $total;
}
?>

The function starts by opening the directory using the opdendir() function. Files and folders are then read using readdir(); The function loops through all items in the folder. A small check is made to verify that only files and folders are considered. Items in the directory are checked whether they are files or folders. In case of files, their size is added to the total size. In case of directories, the contents of those directories must be verified, and therefore the function calls itself. In other words the function goes through all directories and adds up all the file sizes. The function returns an array containing the total size of the directory and the total number of files and of folders in the directory.

<?php
$dirInfo = getDirectorySize(getcwd().'\\Users\\'.$username);

if ($_FILES["file"]["error"] > 0)
    {
        $_SESSION['Error']= "No Upload File Selected";
    }
  else
    {
    if($_FILES["file"]["name"]=="")
    {
    $_SESSION['Error'] = "Maximum size of file per upload is Exceeded.";
    }
     else  if (file_exists($MainDirectory. $_FILES["file"]["name"]))
      {
      $_SESSION['Error'] = $_FILES["file"]["name"] . " already exists.";
      }
    else if ((  $_FILES["file"]["size"] + $dirInfo['size'])> 5242880)
    {
    $_SESSION['Error'] = "Workspace Limit Exceeded, Could not upload file.";

    }
    else
      {
   
      move_uploaded_file($_FILES["file"]["tmp_name"],
      $MainDirectory . $_FILES["file"]["name"]);
    }
}    


header ('Location: FileUploadWelcome.php');
?>

First, the directory size information is retrieved with the function getDirectorySize(). If there is an error, it is reported immediately and no file is uploaded. If the file has no name, it means that an un detected error occured. usually this means that the web server stopped the upload for size limit reasons and no error was reported from the php. In this case an error is assigned to the $_SESSION['Error'] which will later be displayed. The program then checks if the file already exists, if so an error message is reported. Then the size of the directory is added to the sizeof the new file to check whether the WorkSpace size Limit is Exceeded. If not the new file is saved using the function move_uploaded_file().

The image below show the error message displayed when the workspace limit is exceeded.



Deleting Files And Directories

Files and folders, cannot be deleted using the same functions. At first I used two separate links to delete files and folders but that is not necessary, in fact I fixed the code. Functions is_dir() and is_file() can help distinguish between files and folders. Each of the Displayed files has a Link called delete in the same row. The link does not redirect the web page but instead passes a string as parameter. ?Delete="FileName"

Files can be deleted using the function unlink() while folders can be deleted using rmdir(). A problem occurs when you try to delete a folder which is not empty so I added a function to recursively delete the contents of the folder before deleting it.

<?php
function rmdirRec($directory)
 {
     if(substr($directory,-1) == '/')
     {
         $directory = substr($directory,0,-1);
     }
     if(!file_exists($directory) || !is_dir($directory))
     {
         return FALSE;
     }elseif(is_readable($directory))
     {
         $handle = opendir($directory);
         while (FALSE !== ($item = readdir($handle)))
         {
             if($item != '.' && $item != '..')
             {
                 $path = $directory.'/'.$item;
                 if(is_dir($path)) 
                 {
                     rmdirRec($path);
                 }else{
                     unlink($path);
                 }
             }
         }
         closedir($handle);
         
             if(!rmdir($directory))
             {
                 return FALSE;
             }
     }
     return TRUE;
 }
?>

I called the function to delete the directories rmdirRec(). First the function adjusts the path and verifies that the folder exists and is a directory. If the directory is readable, it is opened and the function loops through the items in the directory. Files are deleted using unlink() while directories call the function itself recursively. Finally after deleting all the files and folder, the initial directory is deleted. Basically the function starts deleting the lowest directories first.

The following code shows the delete process.
<?php
if(isset($_GET['Delete']) and $_GET['Delete']!="" and $_GET['Delete']!="." and $_GET['Delete']!="..")
{

  $myFile = $MainDirectory.$_GET['Delete'];

  if (file_exists ($myFile) )
      {
      
          if (is_file($myFile))
          {     
               if( unlink($myFile)==false) $_SESSION['Error'] = "Could not Delete directory.";
            }
         else if (is_dir($myFile))
           {
         if( rmdirRec($myFile) ==false) $_SESSION['Error'] = "Could not Delete directory.";
         }        
      header('Location: '. $_SERVER['SCRIPT_NAME']);
      }
}
?>

It is good practice to ask the user if he/she really wants to delete the files and folder, especially if the folders are not empty. I did not do any checking but it should be done in the future. An easy way would be using javascript to display a message in a yes/no box and act depending on the users choice. By using javascript you won't know if a folder is empty or not, so you would have to either display the message to all types of deletion, or find a way to mark empty directories.

Renaming files

Another feature that I decided to add is the renaming of files and Directories. To rename the file I needed to pass both the old and the new file name to the php script. I dicided to use a little javascript for this task. The href for the link is set to javascript:void(0) and on the event on click the following function is executed.

<?php
function Rename(name)
{
var To =  document.getElementById(name).value;
window.location= "?Rename="+name+"&To="+To;
}
?>

Well to be able to follow the function you need to know more about the html. Near each rename link there is a text box whose id is the name of the file to rename. the name input is the name of the file to be changed.
document.getElementById(name).value gets the contents of the textbox (new name). window.location redirects the page and passes parameters to the form.

<?php
if(isset($_GET['Rename']) and isset($_GET['To']) and $_GET['To']!="")
{
$myFile = $MainDirectory.$_GET['Rename'];

 if (file_exists ($myFile) )
      {
      if (file_exists ($MainDirectory.$_GET['To']) )
        {
        $_SESSION['ERROR']="File name already Exists";        }
          else
          {
          rename($myFile,$MainDirectory.$_GET['To']);
          }
      }
      else
      {
      $_SESSION['ERROR']="Could not Rename File";      }
      
      
      header('Location: '. $_SERVER['SCRIPT_NAME']);
}
?>

When the form receives information about for renaming a file, some checking is done to verify that the input is valid. Then a check is done to see if the file to be renamed exists. Then another check is done to see if the new filename is available. If not an error message is displayed. If the new name is available, the file is renamed using the rename() function. This function works with both files and folders.

The image below shows an example of renaming a folder:


Additional Features

In this section I will talk about additional features I did or could have done. Some suggestions were making a version that runs on mobile phones, and create personalised styles.

I tried my web site on a NOKI 3710 Fold that uses an opera mini browser. All website looks and functionality work properly as they should but the design is not really comfortable to work with on this particular device. This is because the Screen size is small and the mobile lacks of good zooming capabilities. The website works much better if the CSS uses percentage as margins instead of fixed length. In fact I tried it and I got Quite satisfying results, but since Modern mobile phones have much better web browsers, there is no need for me to change all of my styles to accommodate old mobile bowers.

Personalised Styles are another suggested feature which is not that hard to obtain. In my Idea, I would create different style sheets and set one as the default. I would allow the user to select the style he prefers and store it in the database in the login table, probably as a number. When the user login in the style sheet number would be put in a session and depending on that number the appropriate style sheet would be used. The coding is not hard to do, but since I lack visual Creativity, it would take too much time for me to create different styles.

One of the requirements was to do not allow user files to be available to other users. For this purpose when files are downloaded, their original path on the server is not visible. This is not all, the folder Users contains a file called '.htaccess'. This file contains the Line: Deny From all. When the apache server reads this file, it does not allow access to the contents of the folder and thus files in the workspaces cannot be accessed other than from the program. This provides a level of security to protect files in uploaded in the workspace.

To improve web usability I added some javascript. I used javascript mainly on text boxes such that when the user presses enter, the form is not submitted immediately, but I emulate a particular button click, depending on the needs. The following is an example that occurs when the user clicks enter on the new folder textbox.

onkeypress='return NewFolder(event)';

function NewFolder(e)
{
 
 var key = getkey(e);
 
 if (key == 13)
  {
 document.getElementById("btnNewFolder").click();
 }
 
 return (key!=13);
} 

function getkey(e)
{
 var key;
 if (window.event)
 {
 key=window.event.keyCode;
 }else
 {
 key=e.which;
 }
return key;
}

In brief the get key function identifies which key is used and returns the key number. The number 13 is the equivalent to carriage return. If the key is not enter, nothing happens. If enter is pressed the function returns false which is also returned in the onkeypress event. This stops the form from submitting. Then the button for the new folder is clicked (emulation).

Another Feature that I included is the upload visuals. The input file looks different on different browsers. To make the website look alike on all browsers I created a textbox and an image and then I placed the input file button on top of the image and textbox. Then I set then opacity of the input to 0. This style works differently on different browsers, so I tried to hit at least the major browsers. When a user clicks on the iamge to upload a file, in reality he is clicking on the file input which is invisible. Using javascript, when a file is uploaded the file name is put in the text box since the original lable that usually displays the file name is also invisible. Everything works in nearly all browsers, but when it comes to mobile phones, it was not a good Idea at all. The opacity style does not work on all mobile phones causing a mess in the visual styling. To put the actual file browser on top of the fake one, I used the z-index styling property.

The image below shows the new upload visuals:  Note that unfortunately this feature is incompatible with some mobile phone browsers:



Error handling is also a feature I felt I should mention. Since I used javascript to display error messages, these are not displayed when the page header changes because the actual javascript is never executed. In these cases, I created a session called ERROR. In this session I save the error messages which I then display when the new page opens. This is the only solution I found for error messages since php does not provide any function of it's own.

The image below shows an example of an error message being displayed using javascript. This particular error occurs when a file is uploaded with the same name of a file already existent in a directory.



The last feature I will mention is the user verification in different stages. The file functions.php contains a method called VerifyUser(). This method verifies if the user exists. Since the username can be stored in a cookie in the remember me feature, it is important to reverify if the user is still valid when he is automatically re logged in. In case the login name is not found valid, a function called logout is called and deletes the current session and cookies and sends the user to the login screen to reverify his details.

Compatibility Issues

When finished from the coding, I started styling and messing up with colours in the hope that I could come with an acceptable design. When I finished the rough design I decided to try it in different browsers.  On the latest browsers every thing looked as it should but when I tried my design on internet explorer 6 and 7, the design turned out to be a complete mess. 

Below is a screen shot of the testing on old browsers. Please ignore the colours, I hadn't decided on the colours yet.



The main problems with my design where the spacing between cells in the HTML table and the messing up of the last row in the table. Since my design worked on all other browser I was not sure what I was looking for. Then I remembered that gmail uses a similar table to mime and using the inspect element I found out that I had some more styling to do. This styling is done by default in modern browsers, but is not the default in old onces. More exactely, I had to add the property cell padding =0 to the table and add the styles border-spacing:0; and border-collapse:collapse;. Fixing margins and padding does the rest. These styles on the other hand make the row corners look slightely different in ie9 than in chrome, but the difference is acceptable.

The image below shows how internet explorer 9 displays corners slightely differently from other browsers including previous IE versions.


The other problem was the Last row of the table was not being displayed as it should. In this case it was more a mistake of mine rather than the old browser incompatibility fault. I wanted to put two dives on the same line. so what I did, I set their size to 50% each and set the style of their container to display:inline-block, which allows the divs to be placed near each other. This feature seems to not be supported in old browsers, but the problem here was that I could have simply inserted the divs in separate table cells, which was in fact my solution to the problem.

Conclusion

The EasyUpload website, has all the functionality requested by this task together with ideas of my own. It wasn't easy at first to write a program for file handling, mostly because I knew nothing about the methods that would be involved. Fortunately php code and examples are easy to find on the internet, with a lot of documentation and line comments that help you understand better their functionality. The hardest part of php is to keep the code structured. Since html, php, javascript and CSS can all be put into one big file, code can be really messy. I separated to separate files as much as I could. Infact files like upload.php , functions.php and encrypt.php could all be included into one file but instead I decided to split the functions in different files to obtain better structuring. I must say that the include function in php helps a lot. Working with php was a nice experience but it made me realise that loosely typed languages are really hard to debug and maintain, and if the code is not structured, it is even harder.

No comments:

Post a Comment