Display image blobs, possible encoding error - php

I have a form where users can upload images to my MySQL database. The table has three columns: id, name and image. Image is a blob column with the default settings. I'm able to store the image data, but when I fetch the data and try to display it on the web page, I just get a broken image (in this case it's a jpeg file).
I suspect something has gone wrong with the encoding somewhere. My upload.php file is encoded in UTF-8 without BOM. This is my upload code:
$image = addslashes(file_get_contents($_FILES['image']['tmp_name']));
$image_name = addslashes($_FILES['image']['name']);
$insert = $conn->prepare('INSERT INTO images VALUES(:id,:name,:image)');
$insert->bindValue(':id', '');
$insert->bindParam(':name', $image_name);
$insert->bindParam(':image', $image);
$insert->execute();
And this is where I try to display the image.
$select = $conn->prepare('SELECT image FROM images WHERE id = 2');
$select->execute();
$display = $select->fetch();
echo '<img src="data:image/jpg;base64,' . base64_encode( $display['image'] ) . '" />';
I watched a video tutorial on blobs in MySQL, where the blob column had the binaryattribute. However, when I try to create a column like that, I get an error 1064. I don't even know it that has got anything to do with this though.

Firstly, you shouldn't be using addslashes() with prepared statements (not that that's your issue here).
By default ->bindParam() defaults to type PDO::PARAM_STR, so you'll need to specify that the data you're passing is not a string.
Try:
$insert->bindParam(':image', $image, PDO::PARAM_LOB);
Storing binary data in a database can lead to all sorts of issues too. I'd recommend storing the file to disk and just storing the path to it in the DB - it has all sorts of advantages.

Related

not completed image after decoding it php Android

PHP:
<?php
require "conn.php";
$cid = "6";// $_POST["cid"];
$mysql_qry = "select image2 from cities where ID = '$cid'";
$result = mysqli_query($conn,$mysql_qry);
$row = mysqli_fetch_array($result);
header('Content-Type: image/png');
echo base64_decode($row["image2"]);
$conn->close();
?>
and this is the result
How to solve that? my photo is almost black!
As i can see you are collecting image source from the database table. You must check that weather your entire image source is saved properly after encoding it. So check the database Column Data Type in which you have stored it i doubt that its not saving the full image source hence further you are not able to get the full image.
Advice : Most probably Best Practice is that you should convert it to image and save it on disk and just save the IMAGE SOURCE PATH on your Database Table Column. And then fetch it to display when required.
Otherwise Your DB will exausted and will start taking time in retrieving the records. Also problem will start in DB Backup and migrations.
If you dont want to follow the advise then change your column type to Either Blob depending on your image size.

PDO Blob Insert Missing Data

I'm utilizing phantom to capture images, then upload them to a centralized MySQL DB.
The issue that I'm running into is that it's consistently cutting the end off of every file I try and push. It doesn't matter if it's .pdf, .png, .docx, .xlsx... it's cutting off part of the file, thereby corrupting it. The weird thing is that it always cuts the same amount off each file.
My SQL insert code is:
$put_linkdata = $DBW->prepare('INSERT `'.$tableD.'` SET
captured = :capture_time,
error = :eYN,
link = :link,
image = :image,
html = :html,
`text` = :plaintext,
file = :file,
mimetype = :mimetype');
$put_linkdata->bindValue(':capture_time', date('Y-m-d H:i:s',$record['timestamp']));
$put_linkdata->bindValue(':link', $item['url']);
$put_linkdata->bindValue(':mimetype', $record['mimetype']);
$put_linkdata->bindParam(':eYN', $record['error'], PDO::PARAM_STR);
$put_linkdata->bindParam(':image', $record_child['image'], PDO::PARAM_LOB);
$put_linkdata->bindParam(':plaintext', $record_child['text'], PDO::PARAM_LOB);
$put_linkdata->bindParam(':html', $record_child['html'], PDO::PARAM_LOB);
$put_linkdata->bindParam(':file', $record_child['file'], PDO::PARAM_LOB);
if($put_linkdata->execute()){
$linkData_record['id'] = $DBW->lastInsertId();
print PHP_EOL.mb_strlen($record_child['image'], '8bit');
print PHP_EOL.PHP_EOL.'~~~~~~~~~~~~~~~~~~~~~~~~~~~'.PHP_EOL.PHP_EOL;
die();
}
else{
throw New Exception('Error inserting linkdata record into archive - SQL error "'.$put_linkdata->queryString.'"'.PHP_EOL.PHP_EOL.$put_linkdata->errorInfo());
}
I've run a ton of tests and everything prior to here the data still maintains integrity, and if I file_put_contents() it's identical to the captured image or file.
Example of images, pulling google.com gives me a 25K image, but the upload is 17.2K. A pdf that's 55K is uploading at 40.7K. Another pdf is 1.5 MB, but uploads at 1.1MB. When I diff the file against the db blob, the blob in the DB is missing content at the bottom of the file.
The size, and content isn't consistent across files, but IS consistent for identical captures.
Anyone have any ideas?
Update
I've narrowed it down to something happening between the prepared statement and the upload.
Also, this happens in both PDO and MySQLI when using a prepared statement. The first assumption was that the charset encoding somewhere is incorrect, however everything is defined as UTF8 (db, table, PDO connection, config files).
Finding out the issue, this post seems rather silly now, but incase anyone runs into this issue in the future...
There's an error with old versions of PHPMyAdmin where it doesn't correctly show or download data in blob columns.

howto determine image type

I have an image from a blob database field.
is there any way to check the mime type of a field without saving?
getimagesize() and mime_content_type()
requires filename...
i want to do something like this:
<img \n" . 'src="data:image/gif;base64,' . $base64 .
'" alt="base64 img" width="80" height="15" />
When you insert file data into your database, you really should be saving the MIME type with it. Detection isn't perfect, and is at least slower.
In any case:
$mime_type = finfo_buffer($f, $imgdata, FILEINFO_MIME_TYPE);
From: Detecting image type from base64 string in PHP
You can inspect the first few bytes in a binary file to determine this. This is called inspecting the "file signature".
Here are some helpful links that I used to write my own code that does this:
bitmap images - Ruby on Rails: How do you check if a file is an image?
GIF and JPG images - http://www.garykessler.net/library/file_sigs.html
PNG images - http://www.w3.org/TR/PNG/#5PNG-file-signature
As far as I'm aware of you cannot do this. It is actually the reason you should always store the image type in the database together with the blob image data.
But basically you can just print the blob data and set your header to show the image in your browser.
header ("Content-type: image/jpeg");
$sql = "SELECT blobfield FROM table WHERE ...";
$result = mysql_query($sql, $conn);
$img = mysql_fetch_row($result);
print $img[0];
It's possible, but you would have to know something about the image types you may encounter. For example, GIF says 'GIF' in the first three bytes of the data.
http://www.onicos.com/staff/iz/formats/gif.html
Using this information you could check the stream from the blob and act accordingly. Not sure if you care about that much work, but it's doable.

how to Display Multiple Images (blob) from mysql using php?

I'm trying to display multiple images using PHP and MySql database, even if using the while loop I don't get all of the images, I only get one, I mean the first one in the table. What's the problem ?
I'm using a table ID_IMAGE (int, pk, auto increment) and myImage (blob)
$query = mysql_query("SELECT myImage FROM image");
while($data=mysql_fetch_array($query)) {
header('Content-type: image/jpg');
echo $data['myImage'];
}
A possible way to solve this problem is to have a separate script to dynamically output the contents of the image eg. :
image.php
header('Content-type: image/jpg');
// DataBase query and processing here...
echo $data['myImage'];
and call it whenever you need to show images stored in your DB eg. inside your loop:
echo '<img src="image.php?id=' . $data['id'] . '">';
But storing images in the database will take a toll on your server and unless they're really small or you have a good reason to do so, you should only store their physical location on the disk.
You can also use this approach if you wish to hide image location from your users, or control access, but there are better and faster alternatives for that case.
Just to mention the possibility to embed the images directly in html by encoding them, you can use this:
$query = "SELECT myImage FROM image";
if ($result = mysqli_query($link, $query)) {
while ($row = mysqli_fetch_assoc($result)) {
echo '<img src="data:image/jpg;base64,' . base64_encode($row['myImage']) . '">';
}
}
Pro:
The browser does not need to load the images over an additional network connection
You can query and display multiple images in one request
Con:
If the image(s) are big and/or there will be many images, the page will be load slow
Encoding an image to base64 will make it about 30% bigger.
For more information about base encode images:
http://davidbcalhoun.com/2011/when-to-base64-encode-images-and-when-not-to/
base64 encoded image size

Uploaded images to mysql database, but can I retrieve it for an edit page?

$fileName = $_FILES['userfile']['name'];
$tmpName = $_FILES['userfile']['tmp_name'];
$fileSize = $_FILES['userfile']['size'];
$fileType = $_FILES['userfile']['type'];
$fp = fopen($tmpName, 'r');
$content = fread($fp, filesize($tmpName));
$content = addslashes($content);
fclose($fp);
if(!get_magic_quotes_gpc())
{
$fileName = addslashes($fileName);
}
$fileName_th = $_FILES['thumbnail']['name'];
$tmpName_th = $_FILES['thumbnail']['tmp_name'];
$fileSize_th = $_FILES['thumbnail']['size'];
$fileType_th = $_FILES['thumbnail']['type'];
$fp_th = fopen($tmpName_th, 'r');
$content_th = fread($fp_th, filesize($tmpName_th));
$content_th = addslashes($content_th);
fclose($fp_th);
if(!get_magic_quotes_gpc())
{
$fileName_th = addslashes($fileName_th);
}
$query = "INSERT INTO Images (profile_id, thumb, name, size, type, content ) ".
"VALUES ('$profile_id', 0, '$fileName', '$fileSize', '$fileType', '$content'),('$profile_id', 1, '$fileName_th', '$fileSize_th', '$fileType_th', '$content_th') ";
$r = mysqli_query($dbc, $query);
echo "<br>$first_name uploaded successfully";
That is the method im using to upload my images to my database. Now, what I want to do is to have an edit page which edits my form elements like text, along with making changes to the images.
I know how to query text elements and place them back into their respective input fields, but how do i do that for files like images?
Side question: What is the best way of "uploading" files to the database? Is it my way? Or is there a way of just writing files to a directory and saving the path in a database?
Good question. You can't in the same sense as text elements as potentially the image would not exist at the same location as you have stored if you are accessing the interface on a different computer.
When I've seen this kind of requirement in the past, the stored image is normally simply displayed and an option to replace/remove it is given. Unlike a text input, you're never going to change part of the image, you're going to change the whole thing so there's no need to provide the stored image path for editing.
Unless you have a specific need to store the file the way you are, one fairly straightforward solution would be to upload the files to a webserver (but not directly to the database) and simply store the link to them (this is what I've done for a podcasting solution, using mp3s rather than images, but much of the idea is the same). With the link, you could simply use <img> tags in your layout where the src field is populated from the information you dropped in your database.
You need to serve them to the client as an image type. Generally, I would implement a view (or page, depending on your terminology ;)) that is used to query for and render the image. For example: http://myurl.com/index.php/images/index/id/[db image pkey] (that is, if you're using an MVC framework such as CI, otherwise you can use any .php file to achieve the same result).
Using the example URL, the controller (images) would be responsible for instantiating an image model that queries the database for the image with the pkey specified in the URL. The view (or page) would take the data result from the model, simply set the Content-type header to whatever the image content type is, and then serve the binary image data to the client.
AFAIK, there's no way to achieve this inline when you're rendering the rest of your form data as it's a different MIME type.
Edit: Having said the above, after a little reading, it seems that you might not want to do this anyway (read this for further details as to why not). It would be better to store them as static images on the file system.
you need just add header like this image.php
<?php
if (!empty($_GET['image']) && $_GET['image'] > 0) {
//Connect to the database
mysql_connect("localhost","root","root");
mysql_select_db("database");
//Select image content
$sql = mysql_query("SELECT `content`, `type` FROM `Images` WHERE profile_id = ".(int)$_GET['image']." LIMIT 1");
$row = mysql_fetch_assoc($sql);
//Just display the image and finish the application
header("Content-type: image/{$row['type']}");
die($row['content']);
}
?>
There can be some bugs. The main thing is to send the proper headers.
To that image you can access with tag like this:
<img src="image.php?image=1" alt="" />
But if you want to display image in the same scene you need encode that to base64 and display inline like this:
//Imagine that we already got content from the database
$row['content'] = base64_encode($row['content']);
//Prepare inline image
$row['content'] = "data:image/{$row['type']};base64,".$row['content'];
//You will get something like this
/*
data:image/png;base64,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%3D
*/
echo "<img src=\"{$row['content']}\" />";

Categories