Uploading files into a MySQL database using PHP

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • Atli
    Recognized Expert Expert
    • Nov 2006
    • 5062

    Uploading files into a MySQL database using PHP

    You may be wondering why you would want to put your files “into” the database, rather than just onto the file-system. Well, most of the time, you wouldn’t.

    In situations where your PHP application needs to store entire files, the preferred method is to save the file onto the server’s file-system, and store the physical location of the file in your database. This is generally considered to be the easiest and fastest way to store files.

    However, you may find yourself in situations where you would want to keep the file itself with the other data in your database. This gives you - or rather: MySQL - complete control over the file data, rather than just the location of the file on the server.

    There are some downsides to this method though, such as; decreased performance and added complexity to both your PHP code and your database structure. This is something you should carefully consider before using this in a real-life application.

    Having said that, this article demonstrates how you can upload a file from a browser into MySQL, and how to send the files back to the browser.

    Before you start
    To get through this smoothly, you should be familiar with the following:

    The battle plan
    As with all programs, before we start writing we need to plan a little ahead. Just so we know what we are going to write before we write it.

    Before we start on the program, we need to design the database. This is not a complex design, as we are not talking about creating some complex filing system. We only need a single table, containing a BLOB field for our file and various other fields to store information on our file, such as name, size, type.

    Now then. The first phase of the program is getting the file from our users onto the server where our PHP can interact with it. This is the simplest part of the process, requiring only a basic HTML form.

    The second phase involves reading the uploaded file, making sure it was uploaded successfully and adding it to the database. This is a similar process as the one used when uploading a file to the file-system, but using the MySQL functions rather than the file-system functions.

    The third phase is to list all files that have been uploaded and saved on the database, with a link so it can be downloaded. The only problem here would be the fact that the file does not exists on the server, so how do we create a link to it? That is a problem handled by phase 4, all we need to do in phase 3 is create a link with the ID of the file to be downloaded embedded in the URL.

    The fourth, and final, part is the one that is most confusing about this process. The part where we fetch the file and send it to the client's browser.
    We start by using the MySQL functions, and the ID sent by phase 3, to fetch the file data from the database. Then we set a few headers, letting the browser know what to expect, before finally sending the contents of the file.

    Now, using this summary as a guide, lets start writing our program.

    Phase 0: Building a database
    The database is simple. One table with a BLOB field for the file data and a few fields for various pieces of information relating to the file:
    [code=mysql]
    CREATE TABLE `file` (
    `id` Int Unsigned Not Null Auto_Increment,
    `name` VarChar(255) Not Null Default 'Untitled.txt',
    `mime` VarChar(50) Not Null Default 'text/plain',
    `size` BigInt Unsigned Not Null Default 0,
    `data` MediumBlob Not Null,
    `created` DateTime Not Null,
    PRIMARY KEY (`id`)
    )
    [/code]
    As you see, we store the file name, including the extension.
    We have the mime type, which we use to let the browser know what kind of file we are dealing with.
    The size of the file in bytes.
    And finally the data itself, in a MediumBlob field.

    Phase 1: Uploading the file
    Now, we need to get the file from the user. The table we designed does not require any additional information from the user, so we will make this simple and create a HTML form with only a single "file" input field and a submit button:
    [code=html]<!DOCTYPE html>
    <head>
    <title>MySQL file upload example</title>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    </head>
    <body>
    <form action="add_fil e.php" method="post" enctype="multip art/form-data">
    <input type="file" name="uploaded_ file"><br>
    <input type="submit" value="Upload file">
    </form>
    <p>
    <a href="list_file s.php">See all files</a>
    </p>
    </body>
    </html>[/code]
    Note the third attribute of the <form> element, "enctype". This tells the browser how to send the form data to the server. As it is, when sending files, this must be set to "multipart/form-data".
    If it is set any other way, or not set at all, your file is probably not going to be transmitted correctly.

    At the bottom, we have a link to the list we will create in phase 3.

    Phase 2: Add the file to the database
    In the form we built in phase 1, we set the action property to "add_file.p hp". This is the file we are going to build it this phase of the process.

    This file needs to check if a file has been uploaded, make sure it was uploaded without errors, and add it to the database:
    [code=php]
    <?php
    // Check if a file has been uploaded
    if(isset($_FILE S['uploaded_file'])) {
    // Make sure the file was sent without errors
    if($_FILES['uploaded_file']['error'] == 0) {
    // Connect to the database
    $dbLink = new mysqli('127.0.0 .1', 'user', 'pwd', 'myTable');
    if(mysqli_conne ct_errno()) {
    die("MySQL connection failed: ". mysqli_connect_ error());
    }

    // Gather all required data
    $name = $dbLink->real_escape_st ring($_FILES['uploaded_file']['name']);
    $mime = $dbLink->real_escape_st ring($_FILES['uploaded_file']['type']);
    $data = $dbLink->real_escape_st ring(file_get_c ontents($_FILES ['uploaded_file']['tmp_name']));
    $size = intval($_FILES['uploaded_file']['size']);

    // Create the SQL query
    $query = "
    INSERT INTO `file` (
    `name`, `mime`, `size`, `data`, `created`
    )
    VALUES (
    '{$name}', '{$mime}', {$size}, '{$data}', NOW()
    )";

    // Execute the query
    $result = $dbLink->query($query );

    // Check if it was successfull
    if($result) {
    echo 'Success! Your file was successfully added!';
    }
    else {
    echo 'Error! Failed to insert the file'
    . "<pre>{$dbL ink->error}</pre>";
    }
    }
    else {
    echo 'An error accured while the file was being uploaded. '
    . 'Error code: '. intval($_FILES['uploaded_file']['error']);
    }

    // Close the mysql connection
    $dbLink->close();
    }
    else {
    echo 'Error! A file was not sent!';
    }

    // Echo a link back to the main page
    echo '<p>Click <a href="index.htm l">here</a> to go back</p>';
    ?>

    [/code]

    Phase 3: Listing all existing files
    So, now that we have a couple of files in our database, we need to create a list of files and link them so they can be downloaded:
    [code=php]<?php
    // Connect to the database
    $dbLink = new mysqli('127.0.0 .1', 'user', 'pwd', 'myTable');
    if(mysqli_conne ct_errno()) {
    die("MySQL connection failed: ". mysqli_connect_ error());
    }

    // Query for a list of all existing files
    $sql = 'SELECT `id`, `name`, `mime`, `size`, `created` FROM `file`';
    $result = $dbLink->query($sql);

    // Check if it was successfull
    if($result) {
    // Make sure there are some files in there
    if($result->num_rows == 0) {
    echo '<p>There are no files in the database</p>';
    }
    else {
    // Print the top of a table
    echo '<table width="100%">
    <tr>
    <td><b>Name</b></td>
    <td><b>Mime</b></td>
    <td><b>Size (bytes)</b></td>
    <td><b>Create d</b></td>
    <td><b>&nbsp; </b></td>
    </tr>';

    // Print each file
    while($row = $result->fetch_assoc( )) {
    echo "
    <tr>
    <td>{$row['name']}</td>
    <td>{$row['mime']}</td>
    <td>{$row['size']}</td>
    <td>{$row['created']}</td>
    <td><a href='get_file. php?id={$row['id']}'>Download</a></td>
    </tr>";
    }

    // Close table
    echo '</table>';
    }

    // Free the result
    $result->free();
    }
    else
    {
    echo 'Error! SQL query failed:';
    echo "<pre>{$dbL ink->error}</pre>";
    }

    // Close the mysql connection
    $dbLink->close();
    ?>[/code]

    Phase 4: Downloading a file
    This part is the one that usually causes the most confusion.

    To really understand how this works, you must understand how your browser downloads files. When a browser requests a file from a HTTP server, the server response will include information on what exactly it contains. These bits of information are called headers. The headers usually include information on the type of data being sent, the size of the response, and in the case of files, the name of the file.

    There are of course a lot of other headers, which I will not cover here, but it is worth looking into!

    Now, this code. We start simply by reading the ID sent by the link in phase 3. If the ID is valid, we fetch the information on the file who's ID we received, send the headers, and finally send the file data:
    [code=php]<?php
    // Make sure an ID was passed
    if(isset($_GET['id'])) {
    // Get the ID
    $id = intval($_GET['id']);

    // Make sure the ID is in fact a valid ID
    if($id <= 0) {
    die('The ID is invalid!');
    }
    else {
    // Connect to the database
    $dbLink = new mysqli('127.0.0 .1', 'user', 'pwd', 'myTable');
    if(mysqli_conne ct_errno()) {
    die("MySQL connection failed: ". mysqli_connect_ error());
    }

    // Fetch the file information
    $query = "
    SELECT `mime`, `name`, `size`, `data`
    FROM `file`
    WHERE `id` = {$id}";
    $result = $dbLink->query($query );

    if($result) {
    // Make sure the result is valid
    if($result->num_rows == 1) {
    // Get the row
    $row = mysqli_fetch_as soc($result);

    // Print headers
    header("Content-Type: ". $row['mime']);
    header("Content-Length: ". $row['size']);
    header("Content-Disposition: attachment; filename=". $row['name']);

    // Print data
    echo $row['data'];
    }
    else {
    echo 'Error! No image exists with that ID.';
    }

    // Free the mysqli resources
    @mysqli_free_re sult($result);
    }
    else {
    echo "Error! Query failed: <pre>{$dbLink->error}</pre>";
    }
    @mysqli_close($ dbLink);
    }
    }
    else {
    echo 'Error! No ID was passed.';
    }
    ?>[/code]
    Any decent browser should be able to read the headers and understand what type of file this is, and that it is to be downloaded, not opened.

    The finish line
    So, as you see, this is not as complex as one might think.

    This code is of course only written for demonstration purposes and I would not recommend using it without adding a little extra security. Un-edited, this code would basically allow anybody to upload anything to your server, which is not a good idea!

    I hope this has been helpful, and I wish you all the best.

    See you around,
    - Atli Þór

    Revisions
    • August 20th, 2008 - Replaced the old mysql functions with the improved mysqli functions.
    • December 12th, 2009 - Updated the introduction to include a bit more detail on the pros and cons of this method. Also improved the code structure a bit. Replaced the mysqli procedural functions with their OOP counterparts. (Thanks to kovik for pointing out the need for these changes!)
  • ifedi
    New Member
    • Jan 2008
    • 60

    #2
    This whole idea of placing files in database BLOB fields, I get the impression it generally isn't a good idea. At least, it does seem quite unpopular. Could you delve a little into the pros and cons of BLOB versus filesystem options for storage of files on the server.
    Thanks.
    Ifedi.

    Comment

    • Markus
      Recognized Expert Expert
      • Jun 2007
      • 6092

      #3
      Originally posted by ifedi
      This whole idea of placing files in database BLOB fields, I get the impression it generally isn't a good idea. At least, it does seem quite unpopular. Could you delve a little into the pros and cons of BLOB versus filesystem options for storage of files on the server.
      Thanks.
      Ifedi.
      I guess it depends on what type of app you're thinking of
      Originally posted by grantusmaximus. com
      Storing images in a database allows for all of your data to be central stored which is more portable, and easy to replicate. This solution would likely also be easier for taking a point-in-time backup with referential integrity.

      Which option you choose would really depend on the type application you’re building in my opinion.

      So if you’re building an application with a moderately sized amount of image data, and moderate amount of traffic using a database would be okay as the benefits outway the cost. However if you’re building something like flickr with large amounts of data and high traffic, using the file system would be the advised approach.

      I’ve also heard of a combined solution that could provide the best of both world. This is storing your images in the database to gain the benefits there, but also use filesystem caching of these to obtain the performance benefits.

      Comment

      • Atli
        Recognized Expert Expert
        • Nov 2006
        • 5062

        #4
        Hi.

        In my mind, the main reason for placing files and images into a database is security and control.

        If your files are likely to be accessed very frequently, you may be better of leaving them on the file-system. Fetching them from a database involves a lot of extra overhead which will most likely slow you server down.

        If, however, the files you are storing are of a sensitive nature, storing them in a database will give you more control over how they are handled. You could even go as far as splitting them up into multiple fields in multiple tables (even multiple database). It allows you a level of control you will generally not have over you file-system (at least not without jumping through several OS dependent hoops).

        Comment

        • jessica87
          New Member
          • May 2008
          • 10

          #5
          hi atli..it's me again...
          this time i want to ask if there is a simple way to remove files that have been uploaded from database?
          now i m using ur coding to upload my files ^_^
          thank u so much for the coding and advice

          Comment

          • msei
            New Member
            • Mar 2009
            • 6

            #6
            Table 'FileStorage.fi leStorage' doesn't exist

            I am new using mysql and php. I tried to follow the example and everything works fine but when I try to download a file, I get the following error message:

            Error! Query failed:
            Table 'FileStorage.fi leStorage' doesn't exist

            Any idea what I did wrong?

            Any help will be appreciated.

            Comment

            • TheServant
              Recognized Expert Top Contributor
              • Feb 2008
              • 1168

              #7
              Originally posted by msei
              I am new using mysql and php. I tried to follow the example and everything works fine but when I try to download a file, I get the following error message:

              Error! Query failed:
              Table 'FileStorage.fi leStorage' doesn't exist

              Any idea what I did wrong?

              Any help will be appreciated.
              I hate to state the obvious but it sounds like you ahve a typo. Look carefully where the word fileStorage was used. Capitals do make a difference, so make sure you didn't mean FileStorage or filestorage. Otherwise paste your download code if you can't see anything and we'll have a look..

              Comment

              • msei
                New Member
                • Mar 2009
                • 6

                #8
                Uploading files into a MySQL database using PHP

                Thank you for the info. It is working now, but I am having a problem when I view the pdf or doc file on the browser, is there a way to do not show as binary, see file attached. I would like it to be download in the desktop instead view it at the browser? Any help will be appreciated

                Thank you in advance.
                Attached Files

                Comment

                • Markus
                  Recognized Expert Expert
                  • Jun 2007
                  • 6092

                  #9
                  Originally posted by msei
                  Thank you for the info. It is working now, but I am having a problem when I view the pdf or doc file on the browser, is there a way to do not show as binary, see file attached. I would like it to be download in the desktop instead view it at the browser? Any help will be appreciated

                  Thank you in advance.
                  Part 4 of the above article shows you how to download a file.

                  Comment

                  • msei
                    New Member
                    • Mar 2009
                    • 6

                    #10
                    Thanks for the info.

                    Comment

                    • popwebgame
                      Banned
                      New Member
                      • Mar 2009
                      • 1

                      #11
                      Oh, thanks,my friend, !

                      Comment

                      • tweeengl
                        New Member
                        • Apr 2009
                        • 4

                        #12
                        help

                        hello;
                        dose any one can help me?? I found the above code perfect but the thing I would like to know is how can I save the changes that going to be made to the file that been opened? For example... if word file is being open and any thing is changed in it how to save this changes again in mysql db :((
                        HEEEEELP

                        Comment

                        • Atli
                          Recognized Expert Expert
                          • Nov 2006
                          • 5062

                          #13
                          Originally posted by tweeengl
                          hello;
                          dose any one can help me?? I found the above code perfect but the thing I would like to know is how can I save the changes that going to be made to the file that been opened? For example... if word file is being open and any thing is changed in it how to save this changes again in mysql db :((
                          HEEEEELP
                          Hi.

                          To do that, you would have to update the existing row in the database with the new data.

                          You could modify the code in phase 2, replacing the INSERT query with an UPDATE query.

                          Comment

                          • tweeengl
                            New Member
                            • Apr 2009
                            • 4

                            #14
                            EDIT file

                            thanx very much for your answer but the problem is still the same because cant take the file new changes after being edit I cant take the new size and new data to be able to update them as they have been inserted at the first place :'(
                            if you can clear that up to me it would be a great help

                            thanx again

                            Comment

                            • Atli
                              Recognized Expert Expert
                              • Nov 2006
                              • 5062

                              #15
                              The process of updating a file, stored in the manner the article describes, is almost exactly the same as uploading a new file.

                              If you want to open, edit, and save a Word document stored in a MySQL database, the file would have to be:
                              1. Downloaded to a client (Phase #4), where it would be edited.
                              2. Uploaded to server again. (Phase #1)
                              3. And finally inserted into the database again. (Phase #2, substituting the INSERT command with a UPDATE command).

                              The only difference between adding a new file and updating an existing one is that in Phase #2, rather than using INSERT to add a new row, you use UPDATE to alter an existing one.

                              That would of course require the client to pass along the ID of the old row, so it could be updated. You could simply add that to the form in Phase #1, which you would then use in Phase #2 in the UPDATE command.

                              Comment

                              Working...