Use MySQL BLOB column with PHP to store .pdf file

Like always I am sharing new things I learn here on my blog. I
was recently working on a requirement for a LAMP stack web
application reporting dashboard in which I needed to store – and
eventually – retrieve a .pdf file. I have read in several places
(this
fantastic book is a great resource
) that a viable option is
storing images or documents (.pdf in this case) in the actual
database table as opposed to on the server file system. MySQL has
the BLOB datatype that can be used to store files such as .pdf,
.jpg, .txt, and the like. In this blog post, I cover how I
accomplished uploading and storing the actual .pdf file in a BLOB
column in MySQL using PHP. Any corrections, tips, pointers, and
recommendations for best practices are always welcome. We all learn
as we go!!!

image of notebooks folded upPhoto
by
Laika Notebooks
on
Unsplash

Self-Promotion:

If you enjoy the content written here, by all means, share this
blog and your favorite post(s) with others who may benefit from or
like it as well. Since
coffee is my favorite drink, you can even buy me one if you would
like!

I am using a table named ‘project_pdf’ with 3 columns (see
accompanying screenshot) to store the data:

  • ‘id’: type INTEGER
  • ‘project_name’: type TEXT
  • ‘pdf_doc’: type BLOB

phpMyAdmin database table descriptionTable
structure for the project_pdf table.

With the below simple HTML web form, we can collect the
‘project_name’ and enable the .pdf file attachment upload:

image of web form in the browserSimple
web form to upload a pdf to the database.

Below is the HTML source code for the above web form:

  <link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"
integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z"
crossorigin="anonymous"/>
    <title>Upload PDF</title>
    </p><h4 class="text-center" style="margin-top:
100px;">Upload A PDF To The Database</h4>
<div class="d-flex justify-content-center align-self-center"
style="margin-top: 115px;">
    <form action="submit.php" method="POST"
accept-charset="utf-8" enctype="multipart/form-data">
        <div class="formgroup container-fluid">
            <label for="project_name">Project
Name</label>
            <input type="text" name="project_name"/>
        </div>
        <div class="formgroup container-fluid">
            <input type="file" name="pdf_file"
accept=".pdf"/>
            <input type="hidden" name="MAX_FILE_SIZE"
value="67108864"/> <!--64 MB's worth in bytes-->
        </div>
        <div >
            <label for="submit">Submit To
Database</label><br />
            <input type="submit" name="submit"/>
        </div>
    </form>
</div>
    <script
src="https://code.jquery.com/jquery-3.5.1.slim.min.js"
integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
crossorigin="anonymous"></script>
    <script
src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"
integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN"
crossorigin="anonymous"></script>
    <script
src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"
integrity="sha384-B4gt1jrGC7Jh4AgTPSdUtOBvfO8shuf57BaghqFfPlYxofvL8/KUEfYiJOMMV+rV"
crossorigin="anonymous"></script>
Looking at the code…

We will use this PHP code stored in a script submit.php –
which is the form action – along with some best practices
utilizing if/else conditional blocks and wrapping all of the
database operations in a try/catch block to complete the .pdf
INSERT in the MySQL BLOB column:

<!?php
if (isset($_POST['submit']) &&
!empty($_FILES['pdf_file']['name'])) {
     //a $_FILES 'error' value of zero means success. Anything else
and something wrong with attached file.
    if ($_FILES['pdf_file']['error'] != 0) {
        echo 'Something wrong with the file.';
    } else { //pdf file uploaded okay.
        //project_name supplied from the form field
        $project_name =
htmlspecialchars($_POST['project_name']);
        //attached pdf file information
        $file_name = $_FILES['pdf_file']['name'];
        $file_tmp = $_FILES['pdf_file']['tmp_name'];
        if ($pdf_blob = fopen($file_tmp, "rb")) {
            try {
                include
__DIR__."/includes/DatabaseConnection.php";
                $insert_sql = "INSERT INTO `project_pdf`
(`project_name`, `pdf_doc`)
                              VALUES(:project_name,
:pdf_doc);";
                $stmt = $pdo->prepare($insert_sql);
                $stmt->bindParam(':project_name',
$project_name);
                $stmt->bindParam(':pdf_doc', $pdf_blob,
PDO::PARAM_LOB);
                if ($stmt->execute() === FALSE) {
                    echo 'Could not save information to the
database';
                } else {
                    echo 'Information saved';
                }
            } catch (PDOException $e) {
                echo 'Database Error '. $e-&gt;getMessage(). '
in '. $e-&gt;getFile().
                    ': '. $e-&gt;getLine();
            }
        } else {
            //fopen() was not successful in opening the .pdf file
for reading.
            echo 'Could not open the attached pdf file';
        }
    }
} else {
    //submit button was not clicked. No direct script
navigation.
    header('Location: choose_file.php');
}
Verify the button is clicked and a file is attached

The first if/else block verifies that the ‘submit’ button
from the form has been clicked and that the ‘pdf_file’ field
has an attachment using the PHP functions isset() and empty() (the
converse of truth by negating with the not ! operator for the
empty() function):

1 isset($_POST['submit']) &&
!empty($_FILES['pdf_file']['name']))

Tip: More validation can be implemented here to
verify the file type is an actual .pdf since that file type is what
we are expecting to store in the database.

Informational: Visit the official PHP online
documentation for more information on isset() and empty().

Check PHP $_FILES array for errors

The $_FILES array provides several related error codes for file
attachments. A value of 0 (zero) means everything is okay with the
file and it is successfully uploaded. In this particular if/else,
block if that value is not 0 (zero), then we echo in the browser
that something is wrong with the file upload:

1 $_FILES['pdf_file']['error'] != 0

Related: See the official PHP online
documentation for more information on file upload errors.

PHP $_POST and $_FILES Data

The $_POST associative array has the value for the
‘project_name’ input field captured in the form and sent
through the HTTP POST method. Likewise, the $_FILES associative
array has several values for a file or attachment. I am assigning 2
of them to variables, but using only one – ['tmp_name'] – in
the subsequent code:

  • ['name'] – The actual file name from the client. (Could be
    used in a file name column if needed
  • ['tmp_name'] – Temporary file name of the uploaded file as
    stored on the server.
1
2
3
$project_name = htmlspecialchars($_POST['project_name']);
$file_name = $_FILES['pdf_file']['name'];
$file_tmp = $_FILES['pdf_file']['tmp_name'];

Related: Read more about POST upload methods in the official
online PHP documentation.

Read in .pdf binary data and prepare to store in MySQL BLOB column
with PHP

The call to fopen() reads in the file in binary format ("rb")
into a ‘$pdf_blob’ variable. If fopen() cannot open the file,
this if/else block echo‘s the message in the else block to the
browser:

1 $pdf_blob = fopen($file_tmp, "rb")

MySQL database connection and prepared statements

Finally, we look at the entire try/catch block.

I have all database connection information stored in a separate
file named DatabaseConnection.php and include it in the script at
this point using the include directive.

Since we are introducing user-supplied input from the web form
into the database, we use prepared statements leveraging the
PHP PDO methods:

  • prepare()
  • bindParam()
  • execute()

INSERT .pdf file into MySQL BLOB column with PHP

If the call to execute() is not successful, we echo a message to
the browser that the information could not be saved. Otherwise, the
data is successfully inserted and we echo ‘Information
saved’:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
try {
    include __DIR__."/includes/DatabaseConnection.php";
    $insert_sql = "INSERT INTO `project_pdf` (`project_name`,
`pdf_doc`)
                  VALUES(:project_name, :pdf_doc);";
    $stmt = $pdo->prepare($insert_sql);
    $stmt->bindParam(':project_name', $project_name);
    $stmt->bindParam(':pdf_doc', $pdf_blob, PDO::PARAM_LOB);
    if ($stmt->execute() === FALSE) {
        echo 'Could not save information to the database';
    } else {
        echo 'Information saved';
    }
} catch (PDOException $e) {
    echo 'Database Error '. $e->getMessage(). ' in '.
$e->getFile().
        ': '. $e->getLine();   
}

Note: It is generally not a good practice to
echo any sort of database error information to the browser. Errors
should be written to a log file instead. However, for the purpose
of this blog post as a learning experience, I echo out any
exceptions that may arise in the catch block.

Using the form to store .pdf in MySQL BLOB column with PHP

Let’s try out the form and PHP code to verify the upload
works. Here is a simple sample .pdf file I created for a demo
run:

image content of pdf documentContents of SamplePDF.pdf document to upload with form.

See this screenshot in which I fill in the ‘project name’
field with a generic ‘First Project’ name and attach the
SimplePDF.pdf file:

image of web form for submitFilled
out web form with pdf attachment for upload.

Upon clicking the ‘Submit’ button, the information is
successfully stored in the database and the success message is
displayed in the browser:

image of browser messageMessage
displayed in the browser after successful pdf upload.

Here is the data saved in the MySQL database table from the
successful upload via our web form and the PHP code:

phpMyAdmin image of record in database tableThe
project_pdf table with inserted pdf and project name.
It works!!!

In the next blog post, I will cover how to retrieve the .pdf
file from the database and display it in the browser. If you see
anything in the code that I can improve on or any mistake, please
let me know via the comments section below.

Additional PHP/MySQL Reading

Be sure and visit these other blog posts I have written on PHP
and MySQL:

Like what you have read? See anything incorrect? Please comment
below and thanks for reading!!!

A Call To Action!

Thank you for taking the time to read this post. I truly hope
you discovered something interesting and enlightening. Please share
your findings here, with someone else you know who would get the
same value out of it as well.

Visit the Portfolio-Projects page to see blog
post/technical writing I have completed for clients.

To receive email notifications (Never Spam)..