Creating a Upload/Download System Using PHP Classes

Making a PHP upload script can be a very challenging task when you are just starting out, heck; it’s still hard to some extent when you are an experienced developer. So today, I’m going to show you how to make one using PHP5 Classes and a simple form. In the script we will be able to upload files with certain file extensions and set a limit to the size of the file we want to upload. This will all go along with a sharing link and a force download script. If you want an easier file upload client, try YouSendIt.

The Basic Upload Form

First we are going to start out just by making our upload form where we will be able to select a file and then press the upload button to upload the file into our certain directory we will define. It is quite basic so you can just copy and paste it.

<form action="<?php echo $_SERVER['PHP_SELF']; ?>" enctype="multipart/form-data" method="post">
<input name="file" type="file" />
<input type="submit" value="Upload" /> </form>

Developing the Upload Class

The Class and Variables

Now we need to start on the server side part of our project. We need to start by defining a simple class with the name of “Upload”. Inside of that we are going to want to have 3 protected variables; $path, $max_file_length, and $extensions. Our $path variable is going to be the relative path to the upload directory. Our $max_file_size variable will be our maximum allowed file size in megabytes and our $extensions variable will be an array with our allowed file extensions.

The Functions

In our class we will have 3 different functions; upload_file(), download_file() and show_notification(). The name of each function should tell you what it does, so we are going to move on and first set up our show_notification function.

Show Notification Function

In our function we are going to pass through 2 different parameters; one for the message or messages and one for the type of noticfiation. (eg: error, notice, success). We will then open a unordered list and echo out each message in a list element inside the list.

public function show_notification($items, $type) {
echo "
<ul class="$type"> \n";
if(count($items) > 1) {
foreach($items as $item) {
echo "
	<li>$item</li>
\n";
}
}
else {
echo "
	<li>$items</li>
\n";
}
echo "</ul>
\n";
}

The Upload Function

Our upload function is next, we want to create a function that takes the uploaded file and move it to our uploads directory so it can be shared and downloaded by other users. We will start by opening up the function and see if the was a post request for upload a file.

public function upload_file() {
//Check for upload request:
if(isset($_FILES['file'])) {
//What to do with the file
}
}

Now we are going to make an array to store the file information in so we can access it easily. There are 5 different items we are going to store in the array; name, type, size, tmp_name and error (if any).

//Set File Information:
$file = array(
'name' => $_FILES['file']['name'],
'type' => $_FILES['file']['type'],
'size' => $_FILES['file']['size'],
'temp' => $_FILES['file']['tmp_name'],
'error' => $_FILES['file']['error']
);

Next, we will check if there is no errors, and if there is not we will file through the file extension to see if that certain file type is allowed. We will use a variable $filetype_ok to check later if the file is in fact an acceptable file to this point. We will use our protected array of $extensions to reference the allowed file types.

 //Check for file error:
if($file['error'] == 0) { foreach($this->extensions as $extension) { if($extension == $file['type']) { //Filetype ok! $filetype_ok = true; } }  //No match but no error: if(!isset($filetype_ok)) { $filetype_ok = false; } } else { //Filetype/error okay?: $filetype_ok = false; }

Then, we need to check if we ended up with $filetype_ok being true or false, and if it is true we will check if our file is a acceptable range size-wise for upload to our server. If it is not a allowed type or is too big for are server we will show a notification using our function.

 

 //Is Filetype ok?
if($filetype_ok) {
//Check if it is under the max size limit
if($file['size'] > ($this->;max_file_size * 1048576)) {
//File ok!, Move file:
else {
$this->show_notification('Your file is too big to upload to our server.', 'error');
}
}
else {
$this->show_notification('File type not allowed.', 'error');
}

Finally, we now have create a unique filename for our file and move it to our upload directory. We will make a unique name by using the mt_rand function and creating a random number 0-5000 then assigning that number to the beginning of our file following an underscore. Then we will use the move_uploaded_file function to move our file. If the file moves successfully we will echo our a sharing link!

//Filename:
$filename = mt_rand(0, 5000) . '_' . $file['name'];

//Now lets more the file:
$move_file = move_uploaded_file($file['temp'], $this->path . $filename . '.');

if($move_file) {
//File uploaded:
$this->show_notification('File successfully uploaded. Look below for status and link.', 'success');
echo '
Download Link:';
echo '
<input id="download" type="text" value="http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'] . '?file=' . $filename . '" />';
}

Our final code for the upload function should look like this.

public function upload_file() {
//Check for upload request:
if(isset($_FILES['file'])) {
//Set File Information:
$file = array(
'name' => $_FILES['file']['name'],
'type' =>; $_FILES['file']['type'],
'size' => $_FILES['file']['size'],
'temp' => $_FILES['file']['tmp_name'],
'error' => $_FILES['file']['error']
);

//Check for file error:
if($file['error'] == 0) {
foreach($this-&gt;extensions as $extension) {
if($extension == $file['type']) {
//Filetype ok!
$filetype_ok = true;
}
}

//No match but no error:
if(!isset($filetype_ok)) {
$filetype_ok = false;
}
}
else {
//Filetype/error okay?:
$filetype_ok = false;
}

//Is Filetype ok?
if($filetype_ok) {
//Check if it is under the max size limit
if($file['size'] < ($this->max_file_size * 1048576)) {
//Filename:
$filename = mt_rand(0, 5000) . '_' . $file['name'];

//Now lets more the file:
$move_file = move_uploaded_file($file['temp'], $this->;path . $filename . '.');

if($move_file) {
//File uploaded:
$this->show_notification('File successfully uploaded. Look below for status and link.', 'success');
echo '
Download Link:';
echo '
<input id="download" type="text" value="http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'] . '?file=' . $filename . '" />';
}
}
else {
$this->show_notification('Your file is too big to upload to our server.', 'error');
}
}
else {
$this->show_notification('File type not allowed.', 'error');
}
}
}

The Download Function

For this upload/download system when a user clicks the sharing link for a file the system will force a download of the file using PHP Headers. This is for the ease of use and it is a way to save bandwidth.We will first see is the file is set through a $_GET variable and then see if that file exists in our upload directory.

function download_file() {
//Check for download request:
if(isset($_GET['file'])) {
//Make sure there is a file before doing anything
if(is_file($this->path . basename($_GET['file']))) {
//Force download through headers:
else {
$this->show_notification('File not found!', 'error');
}
}
}

Now, guess what we have to do, put a little snippet in so the famous Internet Explorer does what we want it to do (Never heard of that before).

//Below required for IE:
if(ini_get('zlib.output_compression')) {
ini_set('zlib.output_compression', 'Off');
}

Finally, we need to set the headers that will force the download. These are pretty generic headers that most can be figured out by just reading the parameters in head functions. Look at the end of the tutorial for a link to all header descriptions.

//Set Headers:
header('Pragma: public');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', filemtime($this->path . basename($_GET['file']))) . ' GMT');
header('Content-Type: application/force-download');
header('Content-Disposition: inline; filename="' . basename($_GET['file']) . '"');
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . filesize($this->path . basename($_GET['file'])));
header('Connection: close');
readfile($this->path . basename($_GET['file']));
exit();

There you have it, the download function is complete and the full upload and download script is complete. Below is the final download function code.

function download_file() {
//Check for download request:
if(isset($_GET['file'])) {
//Make sure there is a file before doing anything
if(is_file($this->path . basename($_GET['file']))) {
//Below required for IE:
if(ini_get('zlib.output_compression')) {
ini_set('zlib.output_compression', 'Off');
}

//Set Headers:
header('Pragma: public');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', filemtime($this->path . basename($_GET['file']))) . ' GMT');
header('Content-Type: application/force-download');
header('Content-Disposition: inline; filename="' . basename($_GET['file']) . '"');
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . filesize($this->path . basename($_GET['file'])));
header('Connection: close');
readfile($this->path . basename($_GET['file']));
exit();
}
else {
$this->show_notification('File not found!', 'error');
}
}
}

Implementing It Into Your PageHere is finally the part that makes it all work, we need to add 3 lines at the top of the file. The first is to include the class, second to create the instance, and third to register the download function.

 

Now just add this one line right before our form (or wherever you want the upload notification/sharing links to show).

The final index file should look like this (This is a example case).

<script type="text/javascript"><!--mce:0--></script>
<div id="wrapper">
<div id="header">
<h1>Creating a Upload/Download System Using PHP Classes</h1>
</div>
<div id="content">
<div id="upload">
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" enctype="multipart/form-data" method="post">
<input id="real_upload" class="hide" name="file" type="file" />
<input id="real_submit" class="hide" type="submit" value="Upload" />
<div id="upload_hack">
<input id="fake_upload" onclick="select_file()" readonly="readonly" />
<input id="fix" onclick="upload_file()" readonly="readonly" value="UPLOAD" /></div>
<br class="fix" />
</form>
<div id="notifications">upload_file(); ?></div>
</div>
</div>
<div id="footer">

<a href="#">Creating a Upload/Download System Using PHP Classes</a> by <a href="tuttoaster.com">tuttoaster.com</a></div>
</div>

As a little bonus you’ll get the CSS for free.

body {
background: #f4f4f4;
font: 12px Arial;
}

h1 {
font: bold 24px Arial;
line-height: 30px;
}

a  {
color: #000;
text-decoration: none;
}

p {
color: #919191;
}

#wrapper {
margin: 0 auto;
width: 425px;
}

#header, #content, #notifications, #footer {
margin: 30px 0;
}

#upload_hack {
margin: -20px 0 0;
}

#upload_hack input {
background: #FFF;
border: 0px solid #e1e1e1;
-webkit-box-shadow: 0px 0px 5px #c4c4c4;
color: #919191;
float: left;
font-weight: bold;
height: 14px;
margin: 0 10px 0 0;
padding: 21px;
width: 253px;
}

#upload_hack #fix {
background: #FFF;
border: 0px solid #e1e1e1;
-webkit-box-shadow: 0px 0px 5px #c4c4c4;
color: #000;
float: left;
font-weight: bold;
height: 14px;
padding: 21px;
width: 68px;
}

#download {
background: #FFF;
border: 0px solid #e1e1e1;
-webkit-box-shadow: 0px 0px 5px #c4c4c4;
color: #919191;
float: left;
font-weight: bold;
height: 14px;
margin: 10px 0 30px 0;
padding: 21px;
width: 385px;
}

.success {
color: #4fc416;
font-weight: bold;
list-style-image: url('success.png');
list-style-type: none;
}

.error {
color: #f05429;
font-weight: bold;
list-style-image: url('error.png');
}

.success li, .error li {
height: 30px;
line-height: 30px;
}

.fix {
clear: both;
}

.hide {
opacity: 0.0;
}

Final Thoughts/Closing CommentsThis upload/download system is nowhere near advanced. This is where you come in, as a developer I love seeing people build off my basic or even advanced scripts and make them better. So here is my challenge to you, download our script and look it over and make any improvement you have for it and post below, we can all learn from each other!

 

Links for header(); Function Information

Please don’t abuse this demo, files will be removed on a weekly base.

This entry was posted on Sunday, August 29th, 2010 at 02:43 and is filed under Tutorials. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

Cody Robertson is a 19 year old freelancer. He is currently attending university, but loves to write and create beautiful websites whenever he can. He ranges with a large spectrum of coding languages, all the way from Objective-C to HTML. Follow Cody on Twitter

About the author Published by Cody Robertson

15 Responses »

  1. The writer obviously does not know what OOP is.

    • I agree this code deserves some refactoring.

    • Oh, Yeah? But i know what is OOP and please stop spamming this blog, even if you’re a robot.

    • Yes, maybe this was not the best example to use Object Oriented Programming is but it still does follow the objective of being able to reuse it in any location.

      With this code you can use $upload->upload_file(); at any location in your site and you will have a working upload form. You will not have to copy and paste each function in there for it to work, which is one of the goals of Object Oriented Programming, to be able to reuse your already written code.

    • That’s true, you can upload a file in a single method call, but the class could be much easier to understand and manage, I’ll give SOME points where I think the class has room for improvement.
      In the upload_file method:

      1. the $file variable could be a property of the class (at least makes sense).
      2. there are some file checks (like size and error) that could be done by a protected method.
      3. at the end of the method some output is echoed, and generally it’s not a good practice. I think it’s better just to return the output or even better to create a public method do get the final result.

      These are just a few refactoring techniques that the class can implement. They’re not mandatory at all, but in the same way OOP is not mandatory too.

    • @Tutorial City,

      You have some good points, which are things I would have done if I was doing this for a actualy system, but I am not.

      This code was crafted for the soul purpose of introducing very basic OOP PHP and working with files in PHP. This is in no way a advanced tutorial.

      Now to your points:
      1) This would be good if I was doing more with the file in a advanced system, but since In this tutorial I am just moving it then I am done with it there is no need to do that.

      2) This, now that I look back, I probably should have done. I think I looked at the size my server allows and put it there. Your right on that part.

      3) I did the printing out information so the code would mimic the design, again, for the sake of the tutorial.

      Hope this clear some things up, writing code for tutorials will never be the same as writing code for actual applications. Close, but not the same.

      Cody.

  2. I’m researching for methods to serve large files with PHP, and I see you use readfile. Which are the benefits to use this function instead of fpassthru and others?

    • I have always used readfile in these situations, I have herd of fpassthru and after reading a bit more about it I have come to the conclusion that with both functions you can get the same functionality in the end.

      One of the differences I noticed was that when using fopen to open the socket that you need to set it in binary mode by appending a “b” example:
      $fp = fopen('filename.file', 'rb');

      Hope this helps.

  3. Great coincidence,
    On 31 August I managed to create my own upload website. Since I’m new to programming it took me a week t figure out a good working script with php.
    I’ll like to try this one out.
    Is it more secure as compared to simply providing a direct link to the files stored in a folder on your website?

    • Well, it depends on your current download system. Letting them execute there HTML/JavaScript/PHP files is a horrible idea, that is why if you do it right, you can force the download and it will work good.

      This is pretty secure if you handle it right.

  4. great work. Always enjoyed reading your articles.

  5. Hello thanks this was just what i was looking for but i get this problem while running the script once i click on upload to upload a file i get this:”Fatal error: Using $this when not in object context in…” could any one help me with this problem or tell me what i have to do to solve it because i’m new to php.

    thanks

  6. first create a file index.php
    after copy this code in it and save it.

    upload

    FILE:

    after that make a new file name upload.php .copy this code and
    past in upload.php

    that is a simple upload script of php.

    note: make a new folder in and rename it to upload .

  7. Your script have an error click here: http://resp3ct.tk and see… i uploaded a file and copy the link, paste and search… and error