Sunday 20th of August 2017 03:16:13 PM

Writing A File Upload Class using PHP

Author: BinaryStar
Version 1.1
Experience Level: Beginner



 

Introduction

Lately I have seen a ton of questions on the message board about uploading files to the server. It seems as if this is an epidemic that needs to be cured. I have written a PHP class for file uploads which some members of the message board have used and it helped to simplify their lives. Today we will attempt to write our own highly customizable file upload class. Before we get started get yourself a soda and something to munch on because this might take a while. Ready....(pause for the gathering of goodies)..okay let's begin.

What is a class and why do I need one?

Well to put it simply a class is a series of functions that work hand and hand to create an outcome. The reason a class works so great with uploading files is because there are a ton of functions one could write that would all depend on each other's outcome before the final result can be determined. For this reason we write a class instead of 10 functions and taking the time to validate each one.

Another beauty of a class is you can call any of the features within the class that you wish. For instance, with this class there will be 'x' amount of functions, all playing their role in the outcome of the actual upload process. If you wish to use this class to only verify a file's size and not upload it to the server, well you can. If you just wanted to get the file's extension and validate it, you could. That is the beauty of a class. If set up properly, classes are artwork, not just heavy amounts of code.

Before you write a class, or anything for that matter, we should try to plan ahead. Let us take some time and figure out what we need to make this class effective. We will need an arrangement of functions all verifying some sort of process and intermingling together. Let us take a step further and break down what individual functions we will be writing today.

  • Validation of file extensions
  • Validation of file sizes
  • Getting file sizes
  • Getting maximum file size allowment
  • Validation of users uploading files
  • Checking to see if the file exists
  • Setting the upload directory
  • Setting the upload log directory
  • Upload process with and without validation

If you are still asking yourself why you need a class the answer is simple. Ever write a great deal of code that works together to fulfill an outcome? Of course you have and you know how tedious it can be. Well with a class, the first time you write the class it will still be tedious and take some time, but after that first time you never have to write it again, all you need to do is call it and the rest is history. Classes along with functions will just make your life easier. With that being said, let us begin.

Do It With Class

PHP Example: (!)

<?php
class Upload_Files {

    var
$temp_file_name;
    var
$file_name;
    var
$upload_dir;
    var
$upload_log_dir;
    var
$max_file_size;
    var
$banned_array;
    var
$ext_array;
?>

The above snippet of code is the beginning of the class. You must start all classes with the word 'class'. Directly after the word 'class' is the class name. You can name this whatever you would like and stick with your naming conventions, but for this exercise I named it 'Upload_Class'. Following the class name is the opening bracket for the class. You need this to tell PHP - "Hey my class is starting, let's get it on". This may seem a bit remedial for some users, but not everyone is as comfortable with syntax as the more experienced scripters, so please bear with me.

Directly under the beginning of the class we must declare our variables for this class. Basically these are the variables that can be included from the outside of the class by the end user. Just like functions can take arguments, classes can as well, just with a bit different syntax. These lines are just telling the class that these variables can be defined by the user. Variables being used by the class must first be defined as 'var $variable_name'.

Function #1 (Validation of File Extensions)

PHP Example: (!)

<?php
function validate_extension() {
    
//SECTION #1
    
$file_name = trim($this->file_name);
    
$extension = strtolower(strrchr($file_name,"."));
    
$ext_array = $this->ext_array;
    
$ext_count = count($ext_array);

    
//SECTION #2
    
if (!$file_name) {
        return
false;
    } else {
        if (!
$ext_array) {
            return
true;
        } else {
            foreach (
$ext_array as $value) {
                
$first_char = substr($value,0,1);
                    if (
$first_char <> ".") {
                        
$extensions[] = ".".strtolower($value);
                    } else {
                        
$extensions[] = strtolower($value);
                    }
            }

            
//SECTION #3
            
foreach ($extensions as $value) {
                if (
$value == $extension) {
                    
$valid_extension = "TRUE";
                }                
            }

            
//SECTION #4
            
if ($valid_extension) {
                return
true;
            } else {
                return
false;
            }
        }
    }
}
?>

This first function will check to see if the file's extension is valid. How does it do that? Well let's take a look at each section of the code to find out. Firstly to use this function you must include both the file name and an allowable extension array, if you wish to accept all file extensions you do not need to send an extension array. At the end of this tutorial we will go over how to call this entire class and every function in the class, but for right now we are just going to examine the class itself so you can get a clear understanding of this powerful tool.

PHP Example: (!)

<?php
//SECTION #1
$file_name = trim($this->file_name);
$extension = strtolower(strrchr($file_name,"."));
$ext_array = $this->ext_array;
$ext_count = count($ext_array);
?>

Section #1
The first section of this function is just defining the variables to be used with the function.

PHP Example: (!)

<?php
//SECTION #2
if (!$file_name) {
    return
false;
} else {
    if (!
$ext_array) {
        return
true;
    } else {
        foreach (
$ext_array as $value) {
            
$first_char = substr($value,0,1);
                if (
$first_char <> ".") {
                    
$extensions[] = ".".strtolower($value);
                } else {
                    
$extensions[] = strtolower($value);
                }
        }
?>

Section #2
This section of the function starts our validation process for the file extension. First we check to see if a $file_name is present, if it is we continue, otherwise we exit the function and the result will be returned false, because with no file name, we have nothing to examine. Next we check to see if the $ext_array is present. If it is not, it will assume you are accepting all file extensions. Next we start our first foreach loop. This loop will make sure the file extensions begin with a period and are lowercase, if they are not they will be changed to reflect this and sent to another array named $extensions. Now that we have validated that we indeed have a file and a proper extension array we may continue.

PHP Example: (!)

<?php
//SECTION #3
foreach ($extensions as $value) {
    if (
$value == $extension) {
        
$valid_extension = "TRUE";
    }                
}
?>

Section #3
We are now starting yet another loop. We are using our newly defined and organized $extensions array as the focus in this loop. Within the loop is an if statement used to verify if the extension is valid. Basically the if statement says, if the file's extension matches one of the values extracted from the allowable extensions, set the $valid_extension variable to true. This is the core of our function, this section finds out if the file is acceptable or not.

PHP Example: (!)

<?php
            
//SECTION #4
            
if ($valid_extension) {
                return
true;
            } else {
                return
false;
            }
        }
    }
}
?>

Section #4
The last section of the function is just a snippet of code reading if the $valid_extension variable is present. If it is, the function returns true and the file is okay, otherwise the function returns false. There are also (3) closing brackets at the end of the code, (2) are for the above if-elseif statements and the latter one is for the closing of the function. There you have it, you have now just validated against file extensions. That wasn't too hard now was it.

Function #2 (Validation of File Size)

PHP Example: (!)

<?php
function validate_size() {
    
$temp_file_name = trim($this->temp_file_name);
    
$max_file_size = trim($this->max_file_size);

    if (!
$temp_file_name) {
        
$size = filesize($temp_file_name);
            if (
$size > $max_file_size) {
                return
false;                                                        
            } else {
                return
true;
            }
    } else {
        return
false;
    }    
}
?>

Since this function is considerably smaller than the last one, we will just run thru it as a whole instead of breaking into sections. The first (2) lines are just defining the $temp_file_name and $max_file_size which should be supplied by the end user upon the class call. Next we start our if-elseif statements. First we check to see if the $temp_file_name is present, if it is not, we exit the function and it returns false. If the $temp_file_name is present we extract the file's size and compare it to the $max_file_size allowed. If the file's size is greater than the max the function returns false, otherwise it returns true and the file size is valid. This is a pretty straight forward function.

Function #3 (Does This File Already Exist?)

PHP Example: (!)

<?php
function existing_file() {
    
$file_name = trim($this->file_name);
    
$upload_dir = $this->get_upload_directory();

    if (
$upload_dir == "ERROR") {
        return
true;
    } else {
        
$file = $upload_dir . $file_name;
        if (
file_exists($file)) {
            return
true;
        } else {
            return
false;
        }
    }    
}
?>

This function will check to see if the file trying to get uploaded already exists on the server. This function was added upon request and I did not go into it that much. Basically you should have some kind of pre-naming system that you use before you even think about uploading to the server. For instance when I allow users to upload to the server, there must be a record in a database somewhere about this file. So I take the id number from the database and rename the file they submitted to the id number. (ie. user submits hello_world.php, it gets changed to 452.php because this is the 452nd record in the DB) This is a very good naming system because it is extremely easy to delete and update records. There is no rename function included in this class but you could easily add one. With that being said, let us review this code.

The first (2) lines of this function are just declaring the $file_name and $upload_dir. Next we start our if-elseif statement. First we check to see if we have a valid upload directory. If not, we exit the function and return true. I know it seems backwards to return true when the file exists or there is an error but for this function it makes sense. The function's name is 'exisiting_file()', so if it returns true it is essentially saying that the file exists and should not be uploaded. If the upload directory is valid we continue to the next section of the if-elseif statement.

Now we figure the path to our file with the file name intact, ie. $file = $upload_dir . $file_name. Then we have a small snippet of code that uses the PHP function file_exists(). If the file exists, we return true, otherwise we return false and the file is okayed to be uploaded.

Function #4 (Extract The File's Size)

PHP Example: (!)

<?php
function get_file_size() {
    
//SECTION #1
    
$temp_file_name = trim($this->temp_file_name);
    
$kb = 1024;
    
$mb = 1024 * $kb;
    
$gb = 1024 * $mb;
    
$tb = 1024 * $gb;

        
//SECTION #2
        
if ($temp_file_name) {
            
$size = filesize($temp_file_name);
            if (
$size < $kb) {
                
$file_size = "$size Bytes";
            }
            elseif (
$size < $mb) {
                
$final = round($size/$kb,2);
                
$file_size = "$final KB";
            }
            elseif (
$size < $gb) {
                
$final = round($size/$mb,2);
                
$file_size = "$final MB";
            }
            elseif(
$size < $tb) {
                
$final = round($size/$gb,2);
                
$file_size = "$final GB";
            } else { How can XML help app servers do their work? As you can see in Figure 2, in order for the app server to harvest information from such a rich variety of sources, there must be some common ground between all of these sources (each of which might be running on a different hardware and software system). This common ground is the information which flows throughout the entire system, regardless of what source the information comes from. CORBA is an example of tying disparate systems together based on the interfaces that certain remote objects implement. XML does the same thing for data. It allows these disparate systems to share information in a medium that consists only of pure information (and the structural relationships that exist inside of that information). By taking the lowest common denominator approach by using plain text to encode data, XML allows these systems to talk with each other without requiring any special binary information format converters or other service layers to translate between binary formats (for encoding data). Also, since HTTP already supports transmission of plain text, it is completely natural to move XML around using the Hyper Text Transfer Protocol through firewalls and disparate networks. This is shown in Figure 3. XML can be transmitted between systems using one of the most prevalent protocols in use today, Hypertext Transfer Protocol or HTTP 1.1 (which is the protocol of the web).

App server developers are not restricted to using HTTP, they can transmit and recieve XML information using simple remote CORBA objects and RMI objects. The key is that by using XML, it makes these remote services or objects easier to build. And, by sticking with XML, any one of these technologies can be used in your design of your app server. You can use whatever technology is most appropriate to getting the job done, knowing that all the information flows as XML and can be processed by any part of the system. The reason Java object serialization did not achieve this is because it encodes object data to a binary format that is dependent on too many things (like the JVM version, and the existence of classes when things are deserialized, etc). XML is not limited by any of these restrictions (or problems), which makes it much easier to create systems that allow XML information to flow between different subsystems. Also by relying only on the data, large portions of the system can be replaced with better or different implementations for future-readiness.

App servers traditionally give their client apps access to information in remote databases, remote file systems, remote object repositories, remote web resources, and even other app servers. All these information sources don't even need to reside on the machine that hosts the app server. These remote resources may be on other machines on the Intranet or the Internet. Using Java and XML, RMI, JDBC, CORBA, JNDI, Servlet and Swing, you can create app servers that can integrate all kinds of remote and local information resources, and client apps that allow you to remotely or locally access this information from the app server.

In the future, with publicly available DTDs that are standardized for each vertical industry, XML based app servers will become very popular. Also when XML schema repositories become available and widely used, app servers will be able to take on a new role and provide application services that are not offered now. Companies will need to share information with other companies in related fields, and each company might have a different software system in which all their data is housed. By agreeing upon a set of DTDs or schemas (encoded in XML), these companies can exchange information with each other regardless of what systems they are using to store this information. If their app servers can exchange XML documents (based on some shared DTD or schema), then these disparate app servers can understand each other and share information. One of the uses for XML foreseen by the W3C is just this, vertical industries (like insurance and health care) creating sets of DTDs and schemas that all companies in the industry agree upon. Then these companies' app servers can talk to each other using some popular protocol (like HTTP or CORBA/IIOP) to exchange information between each other. This has the potential to save a lot of time and money in the daily business operations of these companies.


                
$final = round($size/$tb,2);
                
$file_size = "$final TB";
            }
        } else {
            
$file_size = "ERROR: NO FILE PASSED TO get_file_size()";
        }
        return
$file_size;
}
?>

This function will examine the file to extract the file's actual size formatted for the upload log file. The code is broken down into (2) sections to make it easier to break down for you.

PHP Example: (!)

<?php
    
//SECTION #1
    
$temp_file_name = trim($this->temp_file_name);
    
$kb = 1024;
    
$mb = 1024 * $kb;
    
$gb = 1024 * $mb;
    
$tb = 1024 * $gb;
?>

Section #1
The first section of this function is just defining your variables. We get the temporary name of the file as well as define file sizes for comparison purposes. The file sizes are defined in bytes.

PHP Example: (!)

<?php
    
//SECTION #2
    
if ($temp_file_name) {
        
$size = filesize($temp_file_name);
        if (
$size < $kb) {
            
$file_size = "$size Bytes";
        }
        elseif (
$size < $mb) {
            
$final = round($size/$kb,2);
            
$file_size = "$final KB";
        }
        elseif (
$size < $gb) {
            
$final = round($size/$mb,2);
            
$file_size = "$final MB";
        }
        elseif(
$size < $tb) {
            
$final = round($size/$gb,2);
            
$file_size = "$final GB";
        } else {
            
$final = round($size/$tb,2);
            
$file_size = "$final TB";
        }
    } else {
        
$file_size = "ERROR: NO FILE PASSED TO get_file_size()";
    }
    return
$file_size;
}
?>

Section #2
The second section of this function starts our validation and output process. First we check to if the $temp_file_name is valid, if not, the function returns an error, otherwise the function continues and tries to determine the file's actual size. Upon validation of the $temp_file_name we now get the file's size in bytes from the PHP function filesize(). We would like to have a readable output for our log file as well as our user. Users don't want to see 10240 bytes, they want to see 10 KB. So we set up a simple statement comparing the file's size against different file sizes to return our readable file size. The code is actually pretty self explanatory, it's just basic math.

Function #5 (Extract The Max File Size)

PHP Example: (!)

<?php
function get_max_size() {
    
$max_file_size = trim($this->max_file_size);
    
$kb = 1024;
    
$mb = 1024 * $kb;
    
$gb = 1024 * $mb;
    
$tb = 1024 * $gb;

    if (
$max_file_size) {
        if (
$max_file_size < $kb) {
            
$max_file_size = "max_file_size Bytes";
        }
        elseif (
$max_file_size < $mb) {
            
$final = round($max_file_size/$kb,2);
            
$max_file_size = "$final KB";
        }
        elseif (
$max_file_size < $gb) {
            
$final = round($max_file_size/$mb,2);
            
$max_file_size = "$final MB";
        }
        elseif(
$max_file_size < $tb) {
            
$final = round($max_file_size/$gb,2);
                
$max_file_size = "$final GB";
        } else {
            
$final = round($max_file_size/$tb,2);
            
$max_file_size = "$final TB";
        }
    } else {
        
$max_file_size = "ERROR: NO SIZE PARAMETER PASSED TO  get_max_size()";
    }
        return
$max_file_size;
}
?>

We will not be breaking this function down into sections because it is almost exact to the previous function. The only thing different is it just returns a readable maximum file size to the user. This function would be great to call in the event of the user trying to upload a file that is too large. You could write an error to the screen and use this function to display the maximum file size allowed in a readable format. Again at the end of this tutorial I will breakdown how to call the class and each function, as well as show you examples of why you would call individual functions. Let us move on to Function #6.

Function #6 (Validation of The User)

PHP Example: (!)

<?php
function validate_user() {
    
//SECTION #1
    
$banned_array = $this->banned_array;
    
$ip = trim($_SERVER['REMOTE_ADDR']);
    
$cpu = gethostbyaddr($ip);
    
$count = count($banned_array);

    
//SECTION #2
    
if ($count < 1) {
        return
true;
    } else {
        foreach(
$banned_array as $key => $value) {
            if (
$value == $ip ."-". $cpu) {
                return
false;
            } else {
                return
true;
            }
        }
    }
}
?>

This function will validate against the user trying to upload. The great thing about this class is you can block people from uploading to your server, no matter username no matter anything. It uses a technique of grabbing the IP address as well as the user's host. It combines them together and gives a proper id. Everytime a user uploads a file this information as well as the file name, size, date, and time are written to a text file on the server. If you ever have a problem with someone uploading viruses, you can delete the file, check to see who uploaded the file, and add the IP - Host Name to your banned user's list. If the user is ever found on the list, he/she will not be able to upload files. The code has been broken down into two sections, let's take a detailed look at each section.

PHP Example: (!)

<?php
function validate_user() {
    
//SECTION #1
    
$banned_array = $this->banned_array;
    
$ip = trim($_SERVER['REMOTE_ADDR']);
    
$cpu = gethostbyaddr($ip);
    
$count = count($banned_array);
?>

Section #1
Section one is just defining all your variables going to be used in this particular function. First we define our banned array. If you don't have anyone on your banned array list, you can either send a blank array or just don't send this variable with the class. If the banned array is not found, the function will assume that everyone is allowed to upload and no checks will take place. Secondly we are gathering the user's IP address found in REMOTE_ADDR. Next we get the user's host. Get host is supposed to mean the person's internet host/provider (ISP). Our last variable is just defining the number of elements within the banned users array.

PHP Example: (!)

<?php
    
//SECTION #2
    
if ($count < 1) {
        return
true;
    } else {
        foreach(
$banned_array as $key => $value) {
            if (
$value == $ip ."-". $cpu) {
                return
false;
            } else {
                return
true;
            }
        }
    }
}
?>

Section #2
The second section starts our validation process. It first checks to see if you have anyone in your banned users list. If not then the function returns true, meaning the user can upload. Otherwise the a foreach() loop is started for the array and the value of each key in the array is compared to the $ip - $cpu name. If these (2) values match, the function returns false and the user will NOT be able to upload files, otherwise it returns true and the user will can go about his/her business. After the validation process is complete all ending brackets are aligned with their counterpart and everything closes properly.

Function #7 (Verify The Upload Directory)

PHP Example: (!)

<?php
function get_upload_directory() {
    
//SECTION #1
    
$upload_dir = trim($this->upload_dir);

    
//SECTION #2
    
if ($upload_dir) {
        
$ud_len = strlen($upload_dir);
        
$last_slash = substr($upload_dir,$ud_len-1,1);
            if (
$last_slash <> "/") {
                
$upload_dir = $upload_dir."/";
            } else {
                    
$upload_dir = $upload_dir;
            }

        
//SECTION #3
        
$handle = @opendir($upload_dir);
            if (
$handle) {
                
$upload_dir = $upload_dir;
                
closedir($handle);
            } else {
                
$upload_dir = "ERROR";
            }
    } else {
        
$upload_dir = "ERROR";
    }
    return
$upload_dir;
}
?>

This function will take the upload directory that you set forth and validate it. First it wants to see if the directory you entered was formatted correctly and then it will check to see if the directory exists. Pretty handy feature just in case you miss a keystroke. I broke this code down into (3) sections so I could better explain each key section.

PHP Example: (!)

<?php
    
//SECTION #1
    
$upload_dir = trim($this->upload_dir);
?>

Section #1
You are probably pretty sick of section #1 by now, but this section #1 is no different from any other section #1. If you haven't guessed by now, we are defining variables. I know, I know, but please try to keep you excitement at a minimum so we can finish this tutorial. The only thing we are defining here is the upload directory which should be set by you.

PHP Example: (!)

<?php
    
//SECTION #2
    
if ($upload_dir) {
        
$ud_len = strlen($upload_dir);
        
$last_slash = substr($upload_dir,$ud_len-1,1);
            if (
$last_slash <> "/") {
                
$upload_dir = $upload_dir."/";
            } else {
                    
$upload_dir = $upload_dir;
            }
?>

Section #2
This section again starts our validation process for verifying the upload directory is in working condition. First it checks to see that the upload directory is present. If it is the function will proceed, otherwise it shoots to the bottom and returns an invalid file directory to you, the user. Next we find the directory length using PHP's very own strlen(). The reason for doing this is we need to find the length of the string to extract the last character from the string. So next we use PHP's substr() function to extract the last character from the upload directory string. You will notice ($last_slash = substr($upload_dir,$ud_len-1,1);) that we are subtracting (1) from the length of the directory string, and we have good reason to do this. See we want to extract the last character off of the upload directory. The strlen() function counts the number of characters starting with '1', but when you count character places in a string you start with '0', hence the minus '1' from the overall length. If we did not do this, we would not select the last character, we would select nothing at all.

The reason for selecting the last character is simple. We need to see if it ends in a backslash. If it does not, we must add one for the function to work properly. So we set a variable of $last_slash which selects the last character, if that last character does not equal a backslash, we add one for the user, otherwise we do nothing.

PHP Example: (!)

<?php
        
//SECTION #3
        
$handle = @opendir($upload_dir);
            if (
$handle) {
                
$upload_dir = $upload_dir;
                
closedir($handle);
            } else {
                
$upload_dir = "ERROR";
            }
    } else {
        
$upload_dir = "ERROR";
    }
    return
$upload_dir;
}
?>

Section #3
In this final section we validate the upload directory. First we set our handle for opening the directory. Then we see if the handle will indeed open. If it does open we close the directory and return the upload directory name, otherwise we return an error to tell the user that the directory is invalid. After all validations have taken place we close all of our brackets and move forth.

*You may notice the @ symbol in front of the opendir() function. This symbol is used to suppress all errors associated with a function. See, if the upload directory is invalid, the opendir() function would produce an error because it gets confused, but we do not want the user to see this error, we want to suppress it so it does not conflict with our code.

Function #8 (Verify The Upload Log Directory)

PHP Example: (!)

<?php
function get_upload_log_directory() {
    
$upload_log_dir = trim($this->upload_log_dir);
    if (
$upload_log_dir) {
        
$ud_len = strlen($upload_log_dir);
        
$last_slash = substr($upload_log_dir,$ud_len-1,1);
            if (
$last_slash <> "/") {
                
$upload_log_dir = $upload_log_dir."/";
            } else {
                
$upload_log_dir = $upload_log_dir;
            }
            
$handle = @opendir($upload_log_dir);
                if (
$handle) {
                    
$upload_log_dir = $upload_log_dir;
                    
closedir($handle);
                } else {
                    
$upload_log_dir = "ERROR";
                }
    } else {
        
$upload_log_dir = "ERROR";
    }
    return
$upload_log_dir;
}
?>

We will not be breaking down this function. The reason for this is because it is exactly the same function we just went over except that it validates and returns the upload log directory. What is the upload log directory? This is the directory that you specify upon the class call to place all log files into. Everytime a user uploads a file, a .txt file is written to the server with today's date. If a file already exists for today's date we just append the data to the end, otherwise we start a new file.

The reason for doing this is to see who is uploading what and when. If somebody uploads a virus you will be able to track that user down and enter him/her onto your banned users list. This is a great function to have in any class or script for that matter, that deals with interaction between the public and the server.

Function #9 (Upload The File With No Validation)

PHP Example: (!)

<?php
function upload_file_no_validation() {
    
//SECTION #1
    
$temp_file_name = trim($this->temp_file_name);
    
$file_name = trim(strtolower($this->file_name));
    
$upload_dir = $this->get_upload_directory();
    
$upload_log_dir = $this->get_upload_log_directory();
    
$file_size = $this->get_file_size();
    
$ip = trim($_SERVER['REMOTE_ADDR']);
    
$cpu = gethostbyaddr($ip);
    
$m = date("m");
    
$d = date("d");
    
$y = date("Y");
    
$date = date("m/d/Y");
    
$time = date("h:i:s A");

    
//SECTION #2
    
if (($upload_dir == "ERROR") OR ($upload_log_dir == "ERROR")) {
        return
false;
    } else {
        if (
is_uploaded_file($temp_file_name)) {
            if (
move_uploaded_file($temp_file_name,$upload_dir . $file_name)) {
                
$log = $upload_log_dir.$y."_".$m."_".$d.".txt";
                
$fp = fopen($log,"a+");
                
fwrite($fp,"
$ip-$cpu | $file_name | $file_size | $date | $time"
);
                
fclose($fp);
                return
true;
            } else {
                return
false;    
            }
        } else {
            return
false;
        }
    }
}
?>

This is one of  the two key functions in this class. This function and the one of next page will actually attempt to upload your file. Hallelujah, praise the Lord, after 8 preliminary functions and 'x' amount of lines of code, we are now getting to the good stuff. This function will upload your file with no file or user validation. The only thing it validates are the (2) directories for uploading. If these are incorrect, the file will not be uploaded. If you don't care about file sizes, types, or users, or even if the file already exists, then use this function to upload your script.

This function is broken down into (2) parts to help simplify the process. Let's take a glance at what might go on inside a function like this. (The build up...)

PHP Example: (!)

<?php
    
//SECTION #1
    
$temp_file_name = trim($this->temp_file_name);
    
$file_name = trim(strtolower($this->file_name));
    
$upload_dir = $this->get_upload_directory();
    
$upload_log_dir = $this->get_upload_log_directory();
    
$file_size = $this->get_file_size();
    
$ip = trim($_SERVER['REMOTE_ADDR']);
    
$cpu = gethostbyaddr($ip);
    
$m = date("m");
    
$d = date("d");
    
$y = date("Y");
    
$date = date("m/d/Y");
    
$time = date("h:i:s A");
?>

Section #1
The function must define (12) different variables to get this party started. A list of variables is below with a short description of what what each one represents.

  • $temp_file_name = The temporary file name taken from the file that needs to be uploaded.
  • $file_name = The actual file name taken from the file that needs to be uploaded.
  • $upload_dir = The upload directory returned by the get_upload_directory() function.
  • $upload_log_dir = The upload directory returned by the get_upload_log_directory() function.
  • $file_size = The readable file size returned from the get_file_size() function.
  • $ip = The user's IP address.
  • $cpu = The user's internet host or (ISP)
  • $m = The current month in (2) digit format. (ie. 01)
  • $d = The current day in (2) digit format. (ie. 01)
  • $y = The current year in (4) digit format. (ie. 2003)
  • $date = Today's date as 01/01/2003
  • $time = The current time as 11:12:56 AM
PHP Example: (!)

<?php
    
//SECTION #2
    
if (($upload_dir == "ERROR") OR ($upload_log_dir == "ERROR")) {
        return
false;
    } else {
        if (
is_uploaded_file($temp_file_name)) {
            if (
move_uploaded_file($temp_file_name,$upload_dir . $file_name)) {
                
$log = $upload_log_dir.$y."_".$m."_".$d.".txt";
                
$fp = fopen($log,"a+");
                
fwrite($fp,"
$ip-$cpu | $file_name | $file_size | $date | $time"
);
                
fclose($fp);
                return
true;
            } else {
                return
false;    
            }
        } else {
            return
false;
        }
    }
}
?>

Section #2
This section of the code is where all the magic happens. It starts the validation and upload process. First it checks to make sure that the upload directories are valid, if they are not, the function returns false and exits, otherwise we continue to the next validation process.

Now we make sure that the file got uploaded to the temp directory. See in your php.ini file there is a section that asks for temp upload directory, this is where the file gets uploaded to. After it is uploaded we must take it from this directory and move it to the correct directory. So we first check to make sure it got uploaded to the temp directory using the is_uploaded_file() function. If it did we continue, otherwise the function returns false and exits.

Now we must check to see if the file was able to be moved from the temp directory to the correct directory with the move_uploaded_file() function. If it was then the upload is complete, the function returns true, and an entry is written in today's log file. Again a log file is kept for every single day a file is uploaded. Each log file will be named by today's date. (ie. 07192003.txt) If a file already exists we just append the data to the end of the file, otherwise we start a new file. In each log file the information kept is the ip address, the internet provider, the file name, file size, upload date, and upload time separated by '|'.

If the moving of the file fails the function will return false and then exit. That is all there really is to uploading a file. The actual upload process is easy, it is just all the variables that can and will take place that you have to account for. Let's move on to our last function for this class.

Function #10 (Upload The File With Validation)

PHP Example: (!)

<?php
function upload_file_with_validation() {
    
//SECTION #1
    
$temp_file_name = trim($this->temp_file_name);
    
$file_name = trim(strtolower($this->file_name));
    
$upload_dir = $this->get_upload_directory();
    
$upload_log_dir = $this->get_upload_log_directory();
    
$file_size = $this->get_file_size();
    
$ip = trim($_SERVER['REMOTE_ADDR']);
    
$cpu = gethostbyaddr($ip);
    
$m = date("m");
    
$d = date("d");
    
$y = date("Y");
    
$date = date("m/d/Y");
    
$time = date("h:i:s A");
    
$existing_file = $this->existing_file();    //<-Add On
    
$valid_user = $this->validate_user();        //<-Add On
    
$valid_size = $this->validate_size();        //<-Add On
    
$valid_ext = $this->validate_extension();    //<-Add On

    //SECTION #2
    
if (($upload_dir == "ERROR") OR ($upload_log_dir == "ERROR")) {
        return
false;
    }
    elseif ((((!
$valid_user) OR (!$valid_size) OR (!$valid_ext) OR ($existing_file)))) {
        return
false;
    } else {
        if (
is_uploaded_file($temp_file_name)) {
            if (
move_uploaded_file($temp_file_name,$upload_dir . $file_name)) {
                
$log = $upload_log_dir.$y."_".$m."_".$d.".txt";
                
$fp = fopen($log,"a+");
                
fwrite($fp,"
$ip-$cpu | $file_name | $file_size | $date | $time"
);
                
fclose($fp);
                return
true;
            } else {
                return
false;
            }
        } else {
            return
false;
        }
    }
}
?>

This function is exactly the same thing as the one on the last page except it adds an additional 6 lines of code. There are (4) new variables under section #1. Each one is listed below with a short description.

  • $existing_file = Returns true if the current file name already exists, false if not.
  • $valid_user = Returns the outcome of if the user is valid or not.
  • $valid_size = Lets the function know if the file size is valid.
  • $valid_ext = Calls the validate_extension() function to validate the file's extension.

These (4) lines are needed so we can validate whether or not the file should be allowed to be uploaded. The other line of code that is added is in Section #2 and listed below.

PHP Example: (!)

<?php
    
elseif ((((!$valid_user) OR (!$valid_size) OR (!$valid_ext) OR ($existing_file)))) {
        return
false;
?>

This is our bread and butter of the validation process. If checks to see if the user is valid, the file size is valid, the file extension is valid, and if the file already exists on the server. If everything checks out okay, it goes thru the same process described on the previous page to upload the file and writes a new line to the log file for that date. You could break this function down more to see which section failed if any, so feel free to expand as much as you want. Now all we have to do is call the class.

Calling The Class

Now that we did all that work, let's put this thing to some use. The best thing about this process is after you wrote the class, you never need to do it again. You can just include the class in your file using the include() function and call it. Instead of coding hundreds of lines each time. Now you can code a miniscle amount. Below is the process for calling the class.

PHP Example: (!)

<?php
//SECTION #1
$upload_class = new Upload_Files;
$upload_class->temp_file_name = trim($_FILES['upload']['tmp_name']);
$upload_class->file_name = trim(strtolower($_FILES['upload']['name']));
$upload_class->upload_dir = "uploads/";
$upload_class->upload_log_dir = "uploads/upload_logs/";
$upload_class->max_file_size = 524288;
$upload_class->banned_array = array("");
$upload_class->ext_array = array(".jpg",".gif",".jpeg",".png");

//SECTION #2
$valid_ext = $upload_class->validate_extension();
$valid_size = $upload_class->validate_size();
$valid_user = $upload_class->validate_user();
$max_size = $upload_class->get_max_size();
$file_size = $upload_class->get_file_size();
$upload_directory = $upload_class->get_upload_directory();
$upload_log_directory = $upload_class->get_upload_log_directory();
$upload_file = $upload_class->upload_file_with_validation();
?>

Section #1
In section one we must start the class and define our class variables. When you are starting a new instance of a class you must set a variable to the class. In this case our main class variable is $upload_class, then we start the class. (new Upload_Files) Just type the word new to let PHP know you are starting a new class and call the class name. Next we must define all of our class variables. To define variables we must start with our main class variable, in this case $upload_class. You have to let PHP know that you want this variable to be sent to the class and just not defined in the script. Remember back in the very beginning of the class, the variables that were defined, well now we will activate them. Let's have a quick look at each variable.

  • $upload_class->temp_file_name = trim($_FILES['upload']['tmp_name']); [set the temp file name]
  • $upload_class->file_name = trim(strtolower($_FILES['upload']['name'])); [set the actual file name]
  • $upload_class->upload_dir = "uploads/"; [set the upload directory]
  • $upload_class->upload_log_dir = "uploads/upload_logs/"; [set the upload log directory]
  • $upload_class->max_file_size = 524288; [set the max file size - .5MB or 512KB]
  • $upload_class->banned_array = array(""); [set the banned users array]
  • $upload_class->ext_array = array(".jpg",".gif",".jpeg",".png"); [set the acceptable file extensions]

You would not have to define every variable if you are not planning on using the validation scripts. If you are just going to upload, you only need the first (4) variables defined instead of all (7). Also remember if you do not have a banned users list, you do not have to define one and if you are going to accept all file extensions there is no need to send that variable either.

PHP Example: (!)

<?php
//SECTION #2
$valid_ext = $upload_class->validate_extension();
$valid_size = $upload_class->validate_size();
$valid_user = $upload_class->validate_user();
$max_size = $upload_class->get_max_size();
$file_size = $upload_class->get_file_size();
$upload_directory = $upload_class->get_upload_directory();
$upload_log_directory = $upload_class->get_upload_log_directory();
$upload_file = $upload_class->upload_file_with_validation();
?>

Section #2
The second section calls all the functions in the class. There is no need no call all the functions, I just wanted to show you that you could. A good reason to call all the functions is that you could setup a message return system. By that I mean you could say if !$valid_ext and return an error message to the user stating the file extension is incorrect. You could just call the $file_size and return that number to the user. The only function you need to call to upload files is the last line starting with $upload_file. If you are going to call the function with validation use the last line above, otherwise use the one below.

PHP Example: (!)

<?php
$upload_file
= $upload_class->upload_file_with_no_validation();
?>

Could there possibly be more information. Let's move to our final page and see what is in store.

Congratulations - You're a Class Act!

Pat yourself on the back, you just made it thru a very difficult process. If it doesn't really make sense yet, don't fret it might take a while to sink in. The best thing to do is read thru this tutorial a few times, even print it out for all the help you will need. The entire script is in a zip file below with an extraordinary amount of comments to help simplify the process. If you did not understand classes in general and went ahead with this tutorial, well then God bless you, and I hope classes are a bit more clear for you now. I am going to leave you with a sample code you could use on your page using this class. I am not going to explain this last code, you should be able to figure it out by now. It will also be included in the zip file for download.

*NOTE: If you are trying to validate against multiple uploads, just set a loop for the number of uploads you have and place all the class calling code within the loop. This will then execute the class over and over until the loop and every file has been processed.

PHP Example: (!)

<?php
$upload_class
= new Upload_Files;
$upload_class->temp_file_name = trim($_FILES['upload']['tmp_name']);
$upload_class->file_name = trim(strtolower($_FILES['upload']['name']));
$upload_class->upload_dir = "uploads/";
$upload_class->upload_log_dir = "uploads/upload_logs/";
$upload_class->max_file_size = 5242880;
$upload_class->banned_array = array("");
$upload_class->ext_array = array(".zip",".rar",".ace",".tar");

$valid_ext = $upload_class->validate_extension();
$valid_size = $upload_class->validate_size();
$valid_user = $upload_class->validate_user();
$max_size = $upload_class->get_max_size();
$file_size = $upload_class->get_file_size();
$file_exists = $upload_class->existing_file();

    if (!
$valid_ext) {
        
$result = "The file extension is invalid, please try again!";
    }
    elseif (!
$valid_size) {
        
$result = "The file size is invalid, please try again! The maximum file size is: $max_size and your file was: $file_size";
    }
    elseif (!
$valid_user) {
        
$result = "You have been banned from uploading to this server.";
    }
    elseif (
$file_exists) {
        
$result = "This file already exists on the server, please try again.";
    } else {
        
$upload_file = $upload_class->upload_file_with_validation();
        if (!
$upload_file) {
            
$result = "Your file could not be uploaded!";
        } else {
            
$result = "Your file has been successfully uploaded to the server.";
        }
    }
?>


Tutorial Revision History:

piece of paper. The two are now done being placed on the canvas, andthe plastic attached to the pieces is overlapping.

This is also occurs where multiple margins meet, such as at the endof a list. Adding to the earlier example, let us assume the followingrules:

UL {margin-bottom: 10px;}LI {margin-top: 10px; margin-bottom: 20px;}H1 {margin-top: 28px;}
drawback: a very few early versions of Navigator 4.x could crash whentrying to process an @import statement. This wasquickly fixed, and very few of these versions are still in use.

11.2.3. Fighting Margin Problems with @import

If you want to use margin rules which you knowwon't work in Navigator, use the previous trick and thecascade to your advantage. Let's say you want a document where

The applications that you create with Java and XML will rely on the services provided by your Java XML Parser (using DOM or SAX). The information itself might be stored in a variety of persistence engines (object databases, relational databases, file systems, dynamic websites, etc.). The information however that comes out of these persistence storage engines must be converted to XML (if they are not in XML already). Once this is done, you have to be concerned with the material covered in this document. This document outlines the most popular Java XML application categories that are possible in an environment where data is encoded with XML, where web access is ubiquitous and platform independence is a necessity.

Java Application Layer

All of the code that you write (in your Java classes) might be considered the Java application layer. Other layers are the XML Parser layer, the XML source (that supplies the XML data that is necessary), and the persistence engine (where the data is actually stored and retrieved by the source).

Your code (in the Java application layer) has to make use of the DOM or SAX API and the XML parser in order to access the information in XML documents (that come from your source). The source might be responsible for pulling data from different persistence engines (relational or object databases) and even the web (dynamically generated websites that supply only XML data).

Figure 4-42

Figure 4-42. Vertical alignment with a percentage and a tall image

The 50%-aligned element has its baseline raised 7 pixels (which is half of 14px), not 25 pixels. Also note that the line-box has been made tall enough to accommodate the image. This is actually consistent with the inline box model, because replaced elements have this kind of effect.

We can see the operation of vertical alignment more clearly if we have two images, one of which is vertically aligned with a percentage value. The results, shown in Figure 4-43, are margin: 1em; padding: 0.5em; background: #CCCCCC; width: 50%; float: right;} <P CLASS="pullq"> "The meerkat is a fun, smart, but often exasperating fellow." </P>

Since we've implemented this quote as a paragraph, if we simply float it in place, the top of the pull quote's box will line up with the beginning of the paragraph that comes after the quote in the HTML document. We decide that's okay and end up with what's shown in Figure 11-10.