...

View Full Version : Broken image when called from DB



fl00d
05-19-2008, 06:19 AM
Hi,

I've been working on an image upload script. I've got the upload part working correctly, but I can't seem to properly recall the image from the database and show it. I've been following this tutorial: http://www.spoono.com/php/tutorials/tutorial.php?id=42

Basically, I've got an image upload form that uploads image, opens & reads image, base64_encodes the image and inserts it into a longtext MySQL field.

Then I've got getImage.php, whose job is to pick out the appropriate image (given through the id param - getImage.php?id=x) from the database, decoded the data and then echo it.

Finally, I've got view.php whose job is to actually show the image, through the normal HTML call like so:

<img src="getImage.php?id=2" />

The problem is that view.php doesn't show the image, or can't find it. (Shows the broken image logo). I can't figure out why. At one point, it was working, but then I switched databases and BOOM, broken again :/

Here are the files (all are basic/lacking security... 'cause their basic atm :P)

uploadImage.php

<?php
include_once("/home/flawclan/public_html/xxxxx/class/startclasses.php");
######################################################
#getImage.php v1.0 #
#read file, encode it, decode it and display it again#
######################################################
$upload = $_POST['upload'];
if(isset($upload)){
//PHP file upload vars
$fileError = $_FILES['imageFile']['error'];
$fileName = $_FILES['imageFile']['name'];
$fileSize = $_FILES['imageFile']['size'];
$fileType = $_FILES['imageFile']['type'];
$fileTempName = $_FILES['imageFile']['tmp_name'];
//Custom vars
$maxAllowedSize = 200000;
$finalLocation = "/home/flawclan/public_html/xxxx/projects/getimage/files/{$fileName}";
//check if file was uploaded
try{
if(is_uploaded_file($fileTempName)){
//check extension
if(($fileType != "image/gif") || ($fileSize > $maxAllowedSize)){
throw new Exception("Invalid file!");
//move the file
}else{
$moveFile = move_uploaded_file($fileTempName,$finalLocation);
if(!$moveFile){
throw new Exception("Could not move file!");
}else{
#echo "File sucessfully uploaded!";
#echo "<br />Normal upload: <img src=\"http://www.xxxx.com/test/files/{$fileName}\" />";
}
}
}else{
echo "Upload error: ".$fileError;
}
}catch (Exception $e){
echo $e->getMessage();
}
//try and open it, encode it
$fh = fopen($finalLocation,"r"); //rb = read binary
$binary = fread($fh,$fileSize);
fclose($fh);
$encodedBinary = chunk_split(base64_encode($binary));

$ip = $_SERVER['REMOTE_ADDR'];

$sql= "INSERT INTO `xxxx_images` (`id`,`image`,`posted_ip`) VALUES ('NULL','$encodedBinary','$ip')";
$q = mysql_query($sql);
if(!$q){
die(mysql_error());
}else{
echo 'File has been uploaded.';
}
unlink($finalLocation);


}else{
echo "<form action=\"{$_SERVER['PHP_SELF']}\" method=\"post\" enctype=\"multipart/form-data\" >";
echo "File: <input type=\"file\" name=\"imageFile\" >";
echo "<br /><input type=\"submit\" name=\"upload\" value=\"Upload\" >";
echo "</form>";
}
?>


getImage.php


<?php
include_once("/home/flawclan/public_html/xxxx/class/startclasses.php");
#############################################
#getImage.php #
#gets images from databases depending #
#on page and displays them #
#############################################
$imageId = $_GET['id'];
$errors = array("invalid" => "Invalid image tag!",
"notfound" => "Image not found!"); //error message array
//check if vars are set
if(!empty($imageId)){
try{
//check to make sure id is integer
if(!is_numeric($imageId)){
throw new Exception($errors['invalid']);
}
//if so, setup sql and run query
$sql = "SELECT `id`,`image` FROM `xxxx_images` WHERE `id`='$imageId' LIMIT 1";
$query = mysql_query($sql);
//check query failed
if(!$query){
throw new Exception($errors['invalid']);
//else check for rows
}else{
$num = mysql_num_rows($query);
if($num == 0){
throw new Exception($errors['notfound']);
}elseif($num == 1){
while($row = mysql_fetch_array($query)){
$showImage = $row['image'];
if(empty($showImage)){
$showImage = "http://www.xxxx.com/ad/images/yourad.gif";
echo $showImage;
die();
}else{
$showImage = base64_decode($showImage);
echo $showImage;

}
}
}else{
throw new Exception($errors['invalid']);
}
}
}catch(Exception $e){
echo $e->getMessage();
}
}else{
header("Location: http://www.xxxx.com");
}
?>


view.php

<img src="getImage.php?id=2" />

Any suggestions?

Thanks
-fl00d

CFMaBiSmAd
05-19-2008, 06:42 AM
Unless you have a specific need to store an image in a database, don't. Store it as a file using the file system (that is what file systems are designed to do.)

Database data is stored in a file. When you put an image or any other kind of file into a database, you are storing a file inside of another file. This just adds extra overhead processing to store the file, but more importantly, it adds extra overhead processing every time that file is output or displayed.

Don't use base64 encoding, that adds an average of 33&#37; to the size of the data. It also adds even more extra overhead processing every time that file is output or displayed. If you do need to store an image in a database, use a BLOB data type.

I don't see anywhere in your code where you are storing an image type header or outputting an image type header before the image data is output.

If you browse directly to the url of the image - http://www.ridemtl.com/projects/getimage/getImage.php?id=5 you will get the raw image binary data. This data might or might not be intact, but because there is no image type header, it is not treated as an image by the browser.

Edit: I looked at the tutorial link. The code is non-functional due to the missing image type header (plus the other problems I mentioned.)

fl00d
05-19-2008, 06:48 AM
You are correct, I haven't changed any headers to output an image. According to the tutorial I was following, it wasn't necessary (at least it didn't have it in the script).

Here, this is an excerpt from the tutorial.

But most of you are probably wondering why when you link to a page, you get an image. This is the reason: images arent defined by their 3 letter suffixes (such as jpg or gif), but by how their headers are written. IMAGE.PHP simply echos the image data, and acts like an image even though it just proccesses the request. This is why you get an image. That is written write after the code for view.php

<img src="getImage.php?id=2' />

I'll try outputting with an image header now. On which page should it go though? getImage.php or view.php?

bdl
05-19-2008, 06:49 AM
Some general comments

You don't store the image mime type or size, both what I consider to be essential on properly outputting the image. Related to this is the fact that you fail to use a header() call to set these values.
I've never seen the need to use base64 to encode the file prior to upload, unless you plan on using in some other method than simply calling from a script that outputs an image such as this.
You actually take the time to use move_uploaded_file() to move the file, then read that to upload, then use unlink to delete it. Just read the file stored in $_FILES['imageFile']['tmp_name'] - it's a 'real' file stored temporarily in the filesystem, usually under /tmp.
The function file_get_contents() (http://www.php.net/file_get_contents) is a simpler way to read the file in as a string.
Your SQL statement to store the image is storing the string 'NULL' in the `id` field instead of an actual NULL. I assume your `id` field is an auto_increment INT type field and this can use NULL, 0, or just plain leave the field out of the column list to set the auto_increment value.


It looks as if CFMaBiSmAd covered many of these issues as I was typing..

fl00d
05-19-2008, 07:00 AM
I put

header("Content-Type: image/gif"); on getImage.php before $showImage is echoed, and it gives the error The image http://www.ridemtl.com/projects/getimage/getImage.php?id=2 cannot be displayed because it contains errors.

I've also removed base64 encoding/decoding. Even if my method isn't the most efficient (as pointed out :p), I'd still like to try and get it working (I mean for storing images in database, I'll fix up the file moving and such so it's more efficient).

Any more suggestions/ideas?

CFMaBiSmAd
05-19-2008, 07:02 AM
For your current problem of an invalid image even with the image header, the chunk_split() function is adding newlines that I am not sure that base64 decode removes.

Another thing that comes to mind is text fields have an issue of either adding or truncating trailing white-space (I don't recall which.) This is why you need to use a BLOB data type IF you insist on storing binary data in a database (that is what BLOB data type is for.)

The raw image data I saw contained a lot of white-space. I suspect that the basic concept used in that tutorial was never made functional.

Edit: I'll also echo what bdl stated about the moving the uploaded file then opening and reading it. That is the worst way to do this, but fits with the rest of the problems with the tutorial.

fl00d
05-19-2008, 07:21 AM
Ah well, this is too problematic. I'll go with your original idea of using the file-system. Perhaps later on I'll take another shot at it using BLOB type fields instead.

For now though, I remember reading a post saying their image script had been taken advantage of and a PHP file was uploaded instead of an image (PHP file tricked script by generating an image at same time?). How would I make sure that would not happen?
I thought of perhaps using a .htaccess in the images folder that wouldn't parse PHP files, but I suppose if they were able to get a PHP file in instead of an image it wouldn't be that hard for them to copy the shell to another directory.


****EDIT****
Wow... I got it working. I had forgotten that I had been using output buffering. I removed that (it was in the include file) and now everything seems to be working. Or at least the images show up.



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum