1

I made an upload file code without prepared statements. The file is successfully uploaded. But when I add prepared statements to the code, the contents of the file is not uploaded. Only the file name, size and type and uploaded in the database.

This is the code:

PHP:

<?php
include("config.php");
error_reporting( ~E_NOTICE );
if(isset($_POST['submit'])  ){

//user has the option whether to upload the file or not
if ($_FILES['upload']['size'] != 0 ){

$filename = $con->real_escape_string($_FILES['upload']['name']);
$filedata= $con->real_escape_string(file_get_contents($_FILES['upload']['tmp_name']));
$filetype = $con->real_escape_string($_FILES['upload']['type']);
$filesize = intval($_FILES['upload']['size']);

$allowed =  array('zip','rar', 'pdf', 'doc', 'docx');
$ext = pathinfo($filename, PATHINFO_EXTENSION);

    if(in_array($ext, $allowed)){           

        if($filesize < 2000000) {

            //$query = "INSERT INTO contracts(`filename`,`filedata`, `filetype`,`filesize`) VALUES ('$filename','$filedata','$filetype','$filesize')"; <- old code line

            $query = "INSERT INTO contracts(`filename`,`filedata`, `filetype`,`filesize`) VALUES (?,?,?,?)";

            $stmt = $con->prepare($query);
            $stmt->bind_param("sbsi", $filename, $filedata, $filetype,$filesize);
            $stmt->execute();

            if ($stmt->errno){
            echo "FAILURE!!! " . $stmt->error;
            } else {
            echo "<br>Inserted";
            }
            $stmt->close(); 

            /* if ($con->query($query) === TRUE) <- old code line
            {
            echo "Uploaded<br>";

            } else {
            echo "Error! <br>" . $con->error;
            }   */

        } else {

        $errorMsg = "Sorry, your file is too large. Only 2MB is allowed";
        }

    }else{
        $errorMsg = "Sorry, only zip, rar, pdf, doc & docx are allowed.";        
    }

//if user has no file to upload then proceed to this else statement
} else {

$filename = $con->real_escape_string($_FILES['upload']['name']);
$filetype = $con->real_escape_string($_FILES['upload']['type']);
$filesize = intval($_FILES['upload']['size']);

//$query = "INSERT INTO contracts(`filename`,`filedata`, `filetype`,`filesize`) VALUES ('$filename','$filetype','$filesize')"; <- old code line

$query = "INSERT INTO contracts(`filename`,`filetype`,`filesize`) VALUES (?,?,?)";

            $stmt = $con->prepare($query);
            $stmt->bind_param("ssi", $filename, $filetype,$filesize);
            $stmt->execute();

            if ($stmt->errno){
            echo "FAILURE!!! " . $stmt->error;
            } else {
            echo "<br>Inserted";
            }
            $stmt->close(); 

        /*  if ($con->query($query) === TRUE) <- old code line
            {
            echo "Uploaded<br>";

            } else {
            echo "Error! <br>" . $con->error;
            }   */

}

$con->close(); 
}   

?>

HTML:

<html><head></head>
<body>

<form method="post" action="" enctype="multipart/form-data">
<?php echo $errorMsg; ?>
Upload File:
<input type="file" name="upload" /><br> 
<input type="submit" name="submit" value="Submit"/>
</form>
</body>
</html>

Why is the contents of the file is not uploaded and missing in the database with prepared statements? What is wrong with my code?

16
  • in your query you simply insert filename,filetype,filesize .. and not the file itself .. Commented Apr 3, 2017 at 7:38
  • prepared statement means not to use real_escape_string Commented Apr 3, 2017 at 7:45
  • 1
    you have to read the file content using file_get_content and set to a field Commented Apr 3, 2017 at 7:46
  • 2
    @ima Op is reading the file into $filedata Commented Apr 3, 2017 at 7:48
  • 1
    How is the filedata column defined in your schema Commented Apr 3, 2017 at 7:49

2 Answers 2

2

Have you considered using http://php.net/manual/en/mysqli-stmt.send-long-data.php ((PHP 5, PHP 7) (Assuming your $conn object is good and working).

$stmt = $con->prepare($query);
$null = NULL;
$stmt->bind_param("sbsi", $filename, $filedata, $filetype,$filesize);
$stmt->send_long_data(1, file_get_contents($_FILES['upload']['tmp_name'])); 
$stmt->execute();

PS : 1 represent the bind argument associated staring from 0, in your case the blob (b) is 2nd, so 1 on a 0 count.

THis is untested and i never used it, i just knew i could be done. Hopefully it will help.

More on the oracle blog : https://blogs.oracle.com/oswald/entry/php_s_mysqli_extension_storing

You might want to escape your binary, see Inserting Binary into MySQL BLOB

Another version from php.net :

$stmt = $con->prepare($query);
$null = NULL;
$stmt->bind_param("sbsi", $filename, $filedata, $filetype,$filesize);
$fp = fopen($_FILES['upload']['tmp_name'], "r");
while (!feof($fp)) {
    $stmt->send_long_data(1, fread($fp,$filesize));
}
fclose($fp);
$stmt->execute();
Sign up to request clarification or add additional context in comments.

5 Comments

You could also consider storing only he filepath in your DB and store the file as a file, but this is purely a choice you have to mkae on you needs.
It displayed Warning: : failed to open stream: Invalid argument in C:\xampp\htdocs\contractdb\filetest.php on line 28
change $filedata to your file path $_FILES['upload']['tmp_name'], will edit answer
Good to know, never used it. The only time i stored images in a db was somewhat sensitive data and was years ago. Sorry for making you my tester :)
Also, as mentioned, you might want to escape your data;
-1

If your database column type of filedata is long enough to accept file content, you can do this.

  1. Check the field type of filedata. Suggestion:make type of column filedata a text or blob
  2. Now check if you file is actually uploaded to server. You can do this by printing the file content

Use following code to check if file is actually uploaded

if ($_FILES['upload']['size'] != 0 ){

$filename = $con->real_escape_string($_FILES['upload']['name']);
$filedata= $con->real_escape_string(file_get_contents($_FILES['upload']['tmp_name']));
$filetype = $con->real_escape_string($_FILES['upload']['type']);
$filesize = intval($_FILES['upload']['size']);

$allowed =  array('zip','rar', 'pdf', 'doc', 'docx');
$ext = pathinfo($filename, PATHINFO_EXTENSION);

//Print the details to check if file is actually uploaded. 
//Note: Remove this line after debugging
print_r([$filename, $filedata, $filetype, $filesize, $ext]); exit;

3 Comments

It prints `Array ( [0] => Document 1.docx [1] => a long line of gibberish unicode [2] => application/vnd.openxmlformats-officedocument.wordprocessingml.document [3] => 10964 [4] => docx)
This means the file is being uploaded successfully. Now check your db structure to find if the long string fit in the column filedata. I hope you already fixed this.
I don't know why the downvote here. This is not a full solution to the problem, the original author used my suggestion to troubleshoot their problem and verified the first part of the problem is not there and I think they went forward with next part of the problem

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.