• php
  • 7301
  • 20-3-2008
  • Now, we will make another upload script. But this time we won't save the file in the database. We will only store the file info there but the real file is stored in the file server. We need a little modification to the upload table. Instead of using BLOB datatype we just use VARCHAR to store the file path.
    CREATE TABLE upload2 (
    id INT NOT NULL AUTO_INCREMENT,
    name VARCHAR(30) NOT NULL,
    type VARCHAR(30) NOT NULL,
    size INT NOT NULL,
    path VARCHAR(60) NOT NULL,
    PRIMARY KEY(id)
    );
    The HTML form we use is no different with the previous one since the real changes will take place in the PHP codes.
    <form method="post" enctype="multipart/form-data">
    <table width="350" border="0" cellpadding="1" cellspacing="1" class="box">
    <tr>
    <td width="246">
    <input type="hidden" name="MAX_FILE_SIZE" value="2000000">
    <input name="userfile" type="file" id="userfile">
    </td>
    <td width="80"><input name="upload" type="submit" class="box" id="upload" value=" Upload "></td>
    </tr>
    </table>
    </form>
    Okay, now let's take a look at the upload process. First we need to specify the directory to store the uploaded files. We store the directory name in [color=5C92CC]$uploadDir[/color]. Note that PHP [color=FA0309]must have write access[/color] to [color=5C92CC]$uploadDir[/color] or else the upload will fail. If you're web host using a Linux server you may need to set the permission for the upload directory to 777.
    <?php
    $uploadDir = 'C:/webroot/upload/'; if(isset($_POST['upload']))
    {
    $fileName = $_FILES['userfile']['name'];
    $tmpName = $_FILES['userfile']['tmp_name'];
    $fileSize = $_FILES['userfile']['size'];
    $fileType = $_FILES['userfile']['type']; $filePath = $uploadDir . $fileName; $result = move_uploaded_file($tmpName, $filePath);
    if (!$result) {
    echo "Error uploading file";
    exit;
    } include '../library/config.php';
    include '../library/opendb.php'; if(!get_magic_quotes_gpc())
    {
    $fileName = addslashes($fileName);
    $filePath = addslashes($filePath);
    } $query = "INSERT INTO upload2 (name, size, type, path ) ".
    "VALUES ('$fileName', '$fileSize', '$fileType', '$filePath')"; mysql_query($query) or die('Error, query failed : ' . mysql_error()); include '../library/closedb.php'; echo "<br>Files uploaded<br>"; }
    ?>
    The key here is the [color=A4D867]move_uploaded_file()[/color] function. This function will move the uploaded files from the temporary upload directory to the location that we earlier ( [color=78AB3C]$uploadDir . $fileName[/color] ). If for some reason the functioncannot move the file it will return false and we exit the script because continuing the script is no use.


    Downloading For listing the download files we just need to copy from the previous script. The real difference start when you click on the download link.

    if(isset($_GET['id']))
    {
    include '../library/config.php';
    include '../library/opendb.php'; $id = $_GET['id'];
    $query = "SELECT name, type, size, path FROM upload2 WHERE id = '$id'";
    $result = mysql_query($query) or die('Error, query failed');
    list($name, $type, $size, $filePath) = mysql_fetch_array($result); header("Content-Disposition: attachment; filename=$name");
    header("Content-length: $size");
    header("Content-type: $type"); readfile($filePath); include '../library/closedb.php';
    exit;
    }
    After fetching the file info from the database and sending the required headers the next thing we need to do is read the file content from the server and send it to the browser. We can accomplish this by using [color=5C92CC]readfile()[/color] function. The Problems
    When using this method of uploading files there are two problems that we need to take care of. They are : - Preventing direct access to the uploaded files
    - Handling duplicate file names Preventing direct access
    For this example the upload directory where the files are stored is /home/arman198/public_html/examples/upload/files/. Using your browser you see the upload directory by clicking here. This is ( usually ) a bad thing because anyone can see directly the file list and download them all. If you don't want to prevent people from seeing the content of the upload directory you could create an empty file, name it index.html then put that file to the upload directory. This is certainly not the optimal solution because maybe some people will try guessing the files names. A better approach is to move the upload directory away from your web root. For example, the web root for this site is: /home/arman198/public_html/ to prevent direct listing i can set the upload directory to /home/arman198/upload/. This way an outsider cannot see directly what's inside the upload directory. For example, even if you go to this url : http://www.php-mysql-tutorial.com/../upload/ you can't see the upload directory
    Handling duplicate file names
    When saving the files into the MySQL database we don't have to worry about this. The table for saving the files uses an id as the primary key so even we put ten files with the same name there won't be any problem since we access the files using that unique id. The problem arise when saving the files to file server. The [color=5C92CC]move_uploaded_file()[/color] function will overwrite a file with the same name and this is certainly not a desired behaviour. To prevent this we just need to modify the file name. In this example the file names are changed into a random string, 32 characters long.
    <?php
    // ... same code as before // get the file extension first
    $ext = substr(strrchr($fileName, "."), 1); // make the random file name
    $randName = md5(rand() * time()); // and now we have the unique file name for the upload file
    $filePath = $uploadDir . $randName . '.' . $ext; $result = move_uploaded_file($tmpName, $filePath);
    // ... same code as before }
    ?>
    First we extract the file extension from the file name using [color=5C92CC]strrchr()[/color] function combined with [color=5C92CC]substr()[/color]. Then using [color=5C92CC]md5()[/color] we generate the 32 characters long of random string. It will look something like 7d1d1da5aac5ad72b293165e8e6fe89b. After we join them up we get the new unique file name. This way the chance of stumbling upon a duplicate name problem is very very slim. As for the download part there's no change required. All we did was change the file name on the server so the previous download script ( download2.phps ) will do just fine or this code
    <?php
    error_reporting(E_ALL);
    if(isset($_GET['id']))
    {
    include 'library/config.php';
    include 'library/opendb.php'; $id = $_GET['id'];
    $query = "SELECT name, type, size, path FROM upload2 WHERE id = '$id'";
    $result = mysql_query($query) or die('Error, query failed');
    list($name, $type, $size, $filePath) = mysql_fetch_array($result); header("Content-Disposition: attachment; filename=$name");
    header("Content-length: $size");
    header("Content-type: $type");

    readfile($filePath); include 'library/closedb.php';
    exit;
    } ?> <html>
    <head>
    <title>Download File From MySQL</title>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
    </head> <body>
    <?php
    include 'library/config.php';
    include 'library/opendb.php'; $query = "SELECT id, name FROM upload2";
    $result = mysql_query($query) or die('Error, query failed');
    if(mysql_num_rows($result) == 0)
    {
    echo "Database is empty <br>";
    }
    else
    {
    while(list($id, $name) = mysql_fetch_array($result))
    {
    ?>
    <a href="download2.php?id=<?=$id;?>"><?=$name;?></a> <br>
    <?php
    }
    }
    include 'library/closedb.php';
    ?>
    </body>
    </html>
    That's it. We're done. If you need the source codes for this php upload tutorial you can download them as zip file attatch. Make sure you change the library/config.php file to match your own settings and change the $uploadDir too if necessary.
    كن أول من يقيم الموضوع
    12345