1

I successfully can upload the image into MySQL but when trying to display the image from the MySQL they appear broken.

  $image = $_FILES['image']['tmp_name'];
   $sql = "INSERT INTO images (image,id) VALUES(?,?)";
   $statement = $conn->prepare($sql);
   $statement->bind_param('si', $image, $id);
   $statement->execute();
   
 $check = mysqli_stmt_affected_rows($statement);
 if($check == 1){
   $msg = 'Image was uploaded';
 }else{
   $msg = 'Something went wrong!';
 }
}
?>
<form action="" method="post" enctype="multipart/form-data">
    <input type="file" name="image" />
    <button>Upload</button>
</form>
<?php
    echo $msg;
?>
<?php

$sql = "SELECT image_id, image, id FROM images WHERE id = ?";
$statement = $conn->prepare($sql);
$statement->bind_param('i', $id);
$statement->execute();
$result = $statement->get_result();

foreach($result as $row){
   echo '<img src="data:image/jpg;base64,'.base64_encode($row['image'] ).'" height="200" width="200"/>';
}

Not sure what I did wrong any help would be much appreciated. Just playing around with this type of thing not a production product or I'd have put the form away from the code.

EDIT! database screenshot

So I edited my code as suggested...now the image isn't being saved as a blob at all the blob section is empty which is a issue.

    $msg = '';
$id = $_SESSION['id'];
if($_SERVER['REQUEST_METHOD'] == 'POST')
{
    $tmpName = $_FILES['image']['tmp_name'];

  // Read the file 
  $fp      = fopen($tmpName, 'r');
  $image = fread($fp, filesize($tmpName));
  fclose($fp);
   $sql = "INSERT INTO images (image,id) VALUES(?,?)";
   $statement = $conn->prepare($sql);
   $statement->bind_param('bi', $image, $id);
   $statement->execute();
   
 $check = mysqli_stmt_affected_rows($statement);
 if($check == 1){
   $msg = 'Image was uploaded';
 }else{
   $msg = 'Something went wrong!';
 }
}
?>
<form action="" method="post" enctype="multipart/form-data">
    <input type="file" name="image" />
    <button>Upload</button>
</form>
<?php
    echo $msg;
?>
<?php

$sql = "SELECT image_id, image, id FROM images WHERE id = ?";
$statement = $conn->prepare($sql);
$statement->bind_param('i', $id);
$statement->execute();
$result = $statement->get_result();

foreach($result as $row){
   echo '<img src="data:image/jpg;base64,'.base64_encode($row['image'] ).'" height="200" width="200"/>';
}
?>
Jigsaw
  • 13
  • 4
  • 1
    The `tmp_name` property is a (temporary) filesystem path (a string), not the binary image content – Phil May 14 '22 at 02:57
  • 2
    1) Read this thread, check your base64 string with the online checker it cites: [How to display Base64 images in HTML](https://stackoverflow.com/questions/8499633/how-to-display-base64-images-in-html). Your *FIRST* step is to verify the image data was stored correctly in the DB. Then 2) Definitely follow [Ken Lee's](https://stackoverflow.com/a/72237104/421195) advice below (and "upvote" and/or "accept" his reply). – paulsm4 May 14 '22 at 03:50

1 Answers1

2
  1. Please use fread (or file_get_contents) to get the binary data uploaded and

  2. Please specify "b" (blob) for binary data when using bind_param

  3. For uploading graphic (which for sure is not too small in size), use send_long_data().

Reason:

If data size of a variable exceeds max. allowed packet size (max_allowed_packet), you have to specify b in types and use mysqli_stmt_send_long_data() to send the data in packets.

The above is quoted from the following official documentation: https://www.php.net/manual/zh/mysqli-stmt.bind-param.php

Hence change

 $image = $_FILES['image']['tmp_name'];
 $sql = "INSERT INTO images (image,id) VALUES(?,?)";
 $statement = $conn->prepare($sql);
 $statement->bind_param('si', $image, $id);
 $statement->execute();

to

  $tmpName = $_FILES['image']['tmp_name'];

  // Read the file 
  $fp      = fopen($tmpName, 'r');
  $image = fread($fp, filesize($tmpName));
  fclose($fp);

  // alternative method
  //$image = file_get_contents($tmpName); 

   $sql = "INSERT INTO images (image,id) VALUES(?,?)";
   $statement = $conn->prepare($sql);
   
   $null = NULL; 

   $statement->bind_param('bi', $null, $id);
   $statement->send_long_data(0, $image); 
   $statement->execute();

Note:

The $null variable is needed, because bind_param() always wants a variable reference for a given parameters. In this case the "b" (as in blob) parameter. So $null is just a dummy, to make the syntax work.

In the next step we need to "fill" the blob parameter with the actual data. This is done by send_long_data(). The first parameter of this method indicates which parameter to associate the data with. Parameters are numbered beginning with 0. The second parameter of send_long_data() contains the actual data to be stored.

So, for your case, you may use the following sample code (tested - 100% working):

<?php
session_start();

$servername = "localhost";
$username = "xxxxxx";
$password = "xxxxxxxxxxxx";
$dbname = "xxxxxxx";

// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);

$msg = '';
$id = $_SESSION['id'];

$id=1234;  // I set this value for testing

if($_SERVER['REQUEST_METHOD'] == 'POST')
{
    $tmpName = $_FILES['image']['tmp_name'];

  // Read the file 

  $fp      = fopen($tmpName, 'r');
  $image = fread($fp, filesize($tmpName));
  fclose($fp);


   $sql = "INSERT INTO images (image,id) VALUES(?,?)";

   $statement = $conn->prepare($sql);
   
   $null = NULL; 

   $statement->bind_param('bi', $null, $id);

   $statement->send_long_data(0, $image); 
   $statement->execute();
   
 $check = mysqli_stmt_affected_rows($statement);
 if($check == 1){
   $msg = 'Image was uploaded';
 }else{
   $msg = 'Something went wrong!';
 }
}
?>

<form action="#" method="post" enctype="multipart/form-data">
<input type="file" name="image" />
<button>Upload</button>
</form>

<?php
    echo $msg;
?>
<?php

$sql = "SELECT image_id, image, id FROM images WHERE id = ?";
$statement = $conn->prepare($sql);
$statement->bind_param('i', $id);
$statement->execute();
$result = $statement->get_result();

foreach($result as $row){

echo '<img src="data:image/jpg;base64,'.base64_encode($row['image']).'" height="200" width="200"/>';
echo "<br>";
}

?>
Ken Lee
  • 6,985
  • 3
  • 10
  • 29
  • So when I use the 'bi' in bind_param it causes the image not to upload but if I go back to 'si' it saves the image an is displayed correctly. In the database it's abunch of symbols and weird looking things. Not sure if it saved correctly don't want to go down the road and it corrupts my database. Any suggestions? The Image in the database is labled as blob it was long blob but switched to plain blob. – Jigsaw May 14 '22 at 12:02
  • Hey Ken yeah it’s set as BLOB now it’s not storing the image as a blob at all the field is empty. When it “uploads” unsure what the issue is now. I reposted the code an a screenshot of the database. – Jigsaw May 14 '22 at 14:07
  • `CREATE TABLE `images` ( `image_id` INT(10) NOT NULL AUTO_INCREMENT, `image` BLOB NOT NULL, `posted_on` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, `ID` INT(10) NOT NULL, PRIMARY KEY (`image_id`) USING BTREE )` Here is the scheme of the image database. – Jigsaw May 14 '22 at 14:38
  • Please see my revised answer (with full explanation and a fully working code). Thanks – Ken Lee May 14 '22 at 15:28
  • What would be the best way to make sure only certain image types are uploaded with this type of code? I've looked around but can't find much that made sense to me. I know I can use a array just trying to get a idea. Thanks – Jigsaw May 21 '22 at 02:21