Inserting modified image into a database

See all posts Reply

Inserting modified image into a database new!
by Rocket Dog, 15 years, 9 months ago
There are several posts on this forum from people struggling to insert a modified image into a database. At first I struggled with this as well, but then the light bulb went on and I discovered the solution. I'd like to share it with you now as a form of "payment" for the use of this class. I'm working on my Master's degree in Web Development Technologies at the moment, and this upload class has proven to be extremely useful and saved me a lot of work, so I figured this is the least I could do. (This solution assumes you are using PHP and MySQL, but the same concept applies if you are using a different language/database combination.)

In a nutshell, what you will need to do is to output your modified file to the server, then read it back using PHP. You could also remove the file from the server afterwards if desired, also using PHP (but this is not shown in my code example below). Here is what the code looks like:

include('class.upload.php');
$foo = new upload($_FILES['form_field']);
if ($foo->uploaded) {
  // Modify the image however you like.  For instance...
  $foo->image_convert         = 'jpg';
  $foo->image_resize           = true;
  $foo->image_x                  = 100;
  $foo->image_ratio_y          = true;
  $foo->file_new_name_body = 'image_resized';
  // Store the directory where you want to save the image.
  $directory = "./photos/";
  // Save the modified image to the desired directory on the server.
  $foo->process($directory);
  // File WAS processed successfully.
  if ($foo->processed) {
    // Store the name of the image that was just saved.
    $filename = $foo->file_dst_name;
    // Store the full path to the image.
    $path = $directory . $filename;
    // Using PHP functions, stream the image file data into a "$file" variable.
    // This is what you will later insert into your MySQL database as a BLOB!
    $temp  = fopen($path, 'r');
    $image = fread($temp, filesize($path));
    $file  = addslashes($image);
    fclose($temp);
    // Delete the temporary file(s).
    $foo->clean();
  }
  // File was NOT processed successfully.
  else {
    echo 'error : ' . $foo->error;
  }
// Build a MySQL query string using the "$file" variable into which you streamed the image data.
$query = " INSERT INTO my_table(image_file) VALUES ('$file')";
  .
  // do your database insertion here as usual!
  .
}
// File was NOT uploaded successfully.
else {
  echo 'error : ' . $foo->error;
}
Reply
Re: Inserting modified image into a database new!
by colin, 15 years, 9 months ago
This functionality is already built in the class. You can call Process() with no arguments to get in return the raw content of the picture. You can then save it directly in the database, or output it right away.

Here is your code, using the built-in feature:
include('class.upload.php');
$foo = new upload($_FILES['form_field']);
if ($foo->uploaded) {
  // Modify the image however you like.  For instance...
  $foo->image_convert         = 'jpg';
  $foo->image_resize           = true;
  $foo->image_x                  = 100;
  $foo->image_ratio_y          = true;
  // Call process() without an argument to get the image in return
  $img = $foo->process();
  // File WAS processed successfully.
  if ($foo->processed) {
    // Prepare the query. The content of the image is in $img
    $query = " INSERT INTO my_table(image_file) VALUES ('" . addslashes($img) . "')";
    // Delete the temporary file(s).
    $foo->clean();
  }
}

Note that doing as above is more efficient as you don't have to create an image, read it back, and then delete it. But generally speaking, it is a bad idea to store images in a database, unless they are very small.

To output the image directly into the browser:
$img = $foo->process();
header("Content-type: image/jpeg");
echo $img;
Reply
Re: Inserting modified image into a database new!
by Rocket Dog, 15 years, 9 months ago
In looking at your example code, if I understand you correctly we would need to call the process() function twice if we want to save the file to the server as well as to the database.

First we modify the file and use process($directory) to save the file to the server.

Then, we modify the file again as we did before, and use process() to save the contents of the file to the database as a BLOB.

So we're writing the same code twice (unless of course we create a single function to handle the image modification, and then call that function twice.) Let me know if I understand that correctly.

BTW, the only reason I'm saving the file to the database is because it's part of my masters degree project to compare image retrieval performance between the server and the database. But normally I would never do that in practice.Reply
Re: Inserting modified image into a database new!
by colin, 15 years, 9 months ago
Strictly speaking, you would need to call process() twice to store the image on file and in the database.

But in fact, you can simply retrieve the image content as in my code example, calling process() without an argument, and then you can save the return value to the database, and dump it to the disk too, using for instance imagepng() or any other PHP image functions.

Sa you can call process() once, and save the image content several times if you wish.Reply
Re: Inserting modified image into a database new!
by Rocket Dog, 15 years, 9 months ago
Well yes, but you can't both insert the file into the database and to the server as a file if you also need to modify the file. Reason being, each time you call process() everything gets reset.

So in my case, I want to convert the image format of the original, then save it on disk and also to the database. Then I want to create a thumbnail version, which I also want to save on disk as well as to the database. So in essence I have 4 processes to go through for each uploaded file:

1) Reformat the file and save it on disk.
2) Reformat the file as in #1, then save it to the database.
3) Resize the file as a thumbnail and save it on disk.
4) Resize the file as in #3 and save it to the database.

I can somewhat reduce the amount of code required by creating function "A" that will handle the image reformatting, and function "B" to handle the image resizing. I can then call on function "A" for steps 1 and 2, and function "B" for steps 3 and 4.

But if I've still got this all wrong, feel free to jump in! And thanks for your quick feedback!Reply
Re: Inserting modified image into a database new!
by colin, 15 years, 9 months ago
What about something like this?

include('class.upload.php');
$foo = new upload($_FILES['form_field']);
if ($foo->uploaded) {
  // Your first pass at the image
  $foo->image_convert         = 'png';
  $foo->image_resize          = true;
  $foo->image_x               = 500;
  $foo->image_ratio_y         = true;
  // Call process() without an argument to get the image in return
  $img = $foo->process();
  // File WAS processed successfully.
  if ($foo->processed) {
    // Prepare the query (and then run it). The content of the image is in $img
    $query = " INSERT INTO my_table(image_file) VALUES ('" . addslashes($img) . "')";
    // Store the picture on file, using PHP functions
    imagepng($img, '/home/a/b/c/image.png');
    // Do not delete the temp file as we will do another pass
  }
  // Your second pass at the image (thumbnail)
  $foo->image_convert         = 'png';
  $foo->image_resize          = true;
  $foo->image_x               = 100;
  $foo->image_ratio_y         = true;
  // Call process() without an argument to get the image in return
  $img = $foo->process();
  // File WAS processed successfully.
  if ($foo->processed) {
    // Prepare the query (and then run it). The content of the image is in $img
    $query = " INSERT INTO my_table(thumbnail_file) VALUES ('" . addslashes($img) . "')";
    // Store the picture on file, using PHP functions
    imagepng($img, '/home/a/b/c/thumbnail.png');
    // Delete the temporary file(s).
    $foo->clean();
  }
}
Reply
Re: Inserting modified image into a database new!
by sergio, 10 years, 7 months ago
Where are you actually connection to the database here?Reply
Re: Inserting modified image into a database new!
by Rocket Dog, 15 years, 9 months ago
Yes, I think that will work. I will try it and see. I was trying to accomplish everything strictly through the upload class, but there's no reason to avoid using the built-in PHP functions, I guess! Thanks, and I'll let you know how it goes.Reply
Re: Inserting modified image into a database new!
by colin, 15 years, 9 months ago
I see your point. Using the code above, with the PHP functions, it is true that you are not benefiting from the built-in class functions that are dealing with the files (renaming, overwriting, etc...).

This said, calling process() without an argument, and retrieving the image contents directly is an acceptable low level use of the class. You shouldn't have to write much code on top of it.Reply
Re: Inserting modified image into a database new!
by Rocket Dog, 15 years, 9 months ago
Well, I've been taking a stab at this for a while now, and I can't get past the following PHP error:

Warning: imagejpeg(): supplied argument is not a valid Image resource

For some reason PHP does not like the file contents generated by the statement $img = $foo->process();

Any suggestions?Reply
Re: Inserting modified image into a database new!
by colin, 15 years, 9 months ago
Yes, my mistake... If you use imagejpeg(), you need to have a PHP image resource as an argument. What the class returns is actually the content of the picture (in JPEG, or in PNG, depending on your settings when calling process()), and not a PHP ressource.

So to dump the image on file, you need to do something like this:
$img = $foo->process();
$file = fopen('my_picture.jpg', "wb");
fwrite($file, $img); 
fclose($file);

I don't have time to test but I reckon that is the issue. My apologies for the wrong code in my previous posts.

Note that instead of writing the image content to a file, you could output it to the browser. In this case again, it is not a PHP image resource that you output, but the actual content of the image in JPG:
$img = $foo->process();
header("Content-type: image/jpeg");
echo $img;

Looking at the code of the class again, I should probably modify it so that you can have direct access to the image resource if you wish to pass it though imagejpeg() yourself.Reply
Re: Inserting modified image into a database new!
by Rocket Dog, 15 years, 9 months ago
Yes, that's essentially how I was working around the problem. Thanks again for taking a look at it! I'll look forward to any future modifications you come up with.Reply