Upload, View PDF in PHP

10,686

First add a numeric auto-incrementing id to your table:

ALTER TABLE `tbl_files` 
    ADD `id` INT NOT NULL AUTO_INCREMENT FIRST, 
    ADD PRIMARY KEY (`id`) ;

Then instead of generating a random number with rand(1000,100000) use the automatically generated id as a file name. You get this id after the insert with mysql_insert_id:

upload.php

// [snip]

// fetch original file extension
$extension = pathinfo($final_file, PATHINFO_EXTENSION);

$allowedExtensions = ["jpg", "jpeg", "png", "gif", "pdf", "doc", "docx"];

// check if the file extension is allowed
if (! in_array($extension, $allowedExtensions))
{
    // report error and abort
}

// use a transaction to rollback the insert 
// in case move_uploaded_file fails
mysql_query("BEGIN");

// insert file into database
$sql = "INSERT INTO tbl_files(file,type,size) VALUES('".mysql_real_escape_string($final_file)."','".mysql_real_escape_string($file_type)."','".mysql_real_escape_string($new_size)."')";
mysql_query($sql);

// fetch generated id
$id = mysql_insert_id();

// move file to $folder and rename it to "$id.$extension"
$fileMoved = move_uploaded_file($file_loc,$folder.$id.".".$extension);

if ($fileMoved)
    mysql_query("COMMIT");
else
    // deletes file entry from the db
    mysql_query("ROLLBACK");

I took the time to add escaping to your insert in order to prevent sql injection. If you can, you really shouldn't use the old mysql interface anymore and instead switch to PDO and prepared statements.

Serve your files using the id: view.php?id=1337

<?php
  $id = filter_input(INPUT_GET, "id", FILTER_VALIDATE_INT);

  if (! $id)
       header("HTTP/1.1 400 Bad Request");

  $result = mysql_query("SELECT * FROM tbl_files WHERE id = ".$id);
  // $id is of type int here, so no sql injection possible

  if (! $result)
       header("HTTP/1.0 404 Not Found");

  $file = mysql_fetch_assoc($result);

  // fetch original file extension or store it the database
  $extension = pathinfo($file["file"], PATHINFO_EXTENSION);

  header('Content-type: application/pdf');
  header('Content-Disposition: inline; filename="' . $file["file"] . '"');
  header('Content-Transfer-Encoding: binary');
  header('Accept-Ranges: bytes');
  @readfile("uploads/$id.$extension");
?>

If direct access to your files is possible, you should use it for performance reasons:

  // [snip]

  // fetch original file extension or store it the database
  $extension = pathinfo($file["file"], PATHINFO_EXTENSION);

  // relocate to the pdf file to have apache/nginx/whatever 
  // serve the file instead of the php interpreter
  header("Location: uploads/$id.$extension");

For other readers: If you don't want to grant direct access, but still care about performance, you can use X-Sendfile to serve the files. nginx provides this feature natively. For apache there is a module that sadly doesn't come shipped.

fix for the final script

    <?php
    include_once 'config_db.php';
    if(isset($_POST['btn-upload']))
    {    

        $allowedExtensions = ["jpg", "jpeg", "png", "gif", "pdf", "doc", "docx"];

        $file = $id."-".$_FILES['file']['name'];
        $file_loc = $_FILES['file']['tmp_name'];
        $file_size = $_FILES['file']['size'];
        $file_type = $_FILES['file']['type'];
        $folder="uploads/";

        // new file size in KB
        $new_size = $file_size/1024;  
        // new file size in KB

        // make file name in lower case
        $new_file_name = strtolower($file);
        // make file name in lower case

        $final_file=str_replace(' ','-',$new_file_name);
        $extension = pathinfo($final_file, PATHINFO_EXTENSION);

        // check if the file extension is allowed
        if (! in_array($extension, $allowedExtensions))
        {
            // report error and abort
            echo "<script>", 
                "alert('invalid file extension');",
                "window.location.href='index.php?fail'",
            "</script>";
        }
        else
        {
            $sql = "INSERT INTO tbl_ficheiros(file,type,size) VALUES('".mysql_real_escape_string($final_file)."','".mysql_real_escape_string($file_type)."','".mysql_real_escape_string($new_size)."')";

            mysql_query($sql);

            // fetch generated id
            $id = mysql_insert_id();

            // move file to $folder and rename it to "$id.$extension"
            $fileMoved = move_uploaded_file($file_loc,$folder.$id.".".$extension);

            if ($fileMoved)
            {
                mysql_query("COMMIT");

                echo "<script>", 
                    "alert('successfully uploaded');",
                    "window.location.href='index.php?success'",
                "</script>";
            }
            else
            {
                // deletes file entry from the db
                mysql_query("ROLLBACK");

                echo "<script>", 
                    "alert('error while uploading file');",
                    "window.location.href='index.php?fail'",
                "</script>";
            }
        }
    }
    ?>
Share:
10,686
Slaxer13
Author by

Slaxer13

Updated on June 13, 2022

Comments

  • Slaxer13
    Slaxer13 almost 2 years

    So i was working on a upload, view file for my site but it seems only images and txt files are ready to view, PDF and word documents don't even show. Can someone tell how do i change this so that i can view pdf and word docs in browser?

    Here is the upload.php:

    <?php
    include_once 'dbconfig.php';
    if(isset($_POST['btn-upload']))
    {    
    
        $file = rand(1000,100000)."-".$_FILES['file']['name'];
        $file_loc = $_FILES['file']['tmp_name'];
        $file_size = $_FILES['file']['size'];
        $file_type = $_FILES['file']['type'];
        $folder="uploads/";
    
        // new file size in KB
        $new_size = $file_size/1024;  
        // new file size in KB
    
        // make file name in lower case
        $new_file_name = strtolower($file);
        // make file name in lower case
    
        $final_file=str_replace(' ','-',$new_file_name);
    
        if(move_uploaded_file($file_loc,$folder.$final_file))
        {
            $sql="INSERT INTO tbl_files(file,type,size) VALUES('$final_file','$file_type','$new_size')";
            mysql_query($sql);
            ?>
            <script>
            alert('successfully uploaded');
            window.location.href='index.php?success';
            </script>
            <?php
        }
        else
        {
            ?>
            <script>
            alert('error while uploading file');
            window.location.href='index.php?fail';
            </script>
            <?php
        }
    }
    ?>
    

    And here is the view.php (Updated and working):

     <?php
      $file = 'uploads/.pdf';
      $filename = 'yolo.pdf';
      header('Content-type: application/pdf');
      header('Content-Disposition: inline; filename="' . $filename . '"');
      header('Content-Transfer-Encoding: binary');
      header('Accept-Ranges: bytes');
      @readfile($file);
    ?>
    

    I only need this to be able to view any PDF without having to have a specific name in the code : $filename = 'yolo.pdf';

    I have a list of PDF files for the users to see. Is it possible, when clicking the view button, to read the id of the pdf file in the database and to store it in a variable which will be placed in the code? This way php will view the specific file whithout having to change code for every file...

    I know this may sound a little confusing so any question just say.