Inserting multiple images in mysql, also inserts multiple rows - php

I searched Google all over the place for an answer but I can't seem to find the right one so I'll try it here.
I want to store the users' firstname, lastname and the path of the images in the mysqli database and the image in the folder uploads. (the user can upload multiple images)
This works and is no problem.
The issue is:
When for example they type their firstname and lastname and select two images and press the upload button it uploads everything but it also creates two rows with the exact same values.
I want to store everyting in one row, see my code below:
<?php
$con = mysqli_connect('localhost','root','','img_db');
mysqli_select_db($con,'img_db');
$rn = mt_rand();
if(isset($_POST['submit'])&& isset($_FILES['image'])&& !empty($_POST['firstname'])&& !empty($_POST['lastname']))
{
$firstname = $_POST['firstname'];
$lastname = $_POST['lastname'];
for($i=0; $i<count($_FILES['image']['name']); $i++)
{
$tmp_name = $_FILES['image']['tmp_name'][$i];
$max_size = 100000;
$path = "uploads/";
$name = $_FILES['image']['name'][$i];
$size = $_FILES['image']['size'][$i];
$type = $_FILES['image']['type'][$i];
$ext = strtolower(substr($name, strpos($name, '.') +1));
$name = str_replace('_','',trim($name));
$name = str_replace('-','',trim($name));
$name = str_replace(' ','',trim($name));
$name = str_replace('__','',trim($name));
if(($ext=='jpg' || $ext=='jpeg' || $ext=='png' || $ext=='gif')&&($type=='image/jpeg' || $type=='image/png' || $type=='image/gif')&&$size<=$max_size)
{
if(move_uploaded_file($_FILES['image']['tmp_name'][$i], $path.$rn.$name))
{
mysqli_query($con,"INSERT into `img` (firstname,lastname,url) VALUES('$firstname','$lastname','$rn$name')");
}
}// END EXT
}// END FOR LOOP
}// END IF ISSET POST SUBMIT
?>

Suggestion 1
One solution is to store uploaded file urls in an array (declared before the for loop) and utilize the array outside of the for loop, like so:
if (isset(/* ... */)) {
// Outside your for loop
$files = array();
for (/* .. */) {
// Doing things
if (/* $ext stuff */) {
if (move_uploaded_file(/* ... */))
{
$files[] = $rn.$name;
}
} // End EXT
} // End FOR
// Utilize $files array to determine how you want to store all of these URLs in one field.
// Let's say you created a variable called $store with the desired representation.
mysqli_query($con,"INSERT into `img` (firstname,lastname,url) VALUES('$firstname','$lastname','$store')");
} // End ISSET
Suggestion 2
You could use a two-table structure (one table is users, one table is images) and create a foreign key relation from each image table row to a user table row via the desired user's primary key.
See: http://dev.mysql.com/doc/refman/5.6/en/create-table-foreign-keys.html

Related

How to fetch images that stored in comma separated format in single row in MySQL?

I am uploading multiple images in the database in a single column with comma separated format. I am first creating a folder for each user and inside that folder, images are stored. car_images is my root directory inside that with the name of logged_in user new directory will create.
My images are stored in below format :
Here, emp_code is unique I am using this as SESSION and for the name of the folder of each user.
as you see car_images column where I am storing image name with ,.
I am using below code to stored images in folders and database. I don't know idea how to fetch all images of a single user.
$car_images_all="";
for($i=0; $i<count($_FILES['car_images']['name']); $i++)
{
$tmpFilePath = $_FILES['car_images']['tmp_name'][$i];
if ($tmpFilePath != "")
{
if (!file_exists('car_images/'.$emp_code))
{
mkdir('car_images/'.$emp_code, 0777, true);
}
$location = 'car_images/'.$emp_code.'/';
$name = $_FILES['car_images']['name'][$i];
$size = $_FILES['car_images']['size'][$i];
list($txt, $ext) = explode(".", $name);
$file= time().substr(str_replace(" ", "_", $txt), 0);
$info = pathinfo($file);
$filename = $file.".".$ext;
if(move_uploaded_file($_FILES['car_images']['tmp_name'][$i], $location.$filename))
{
$car_images_all.=$filename.",";
}
}
}
First of all,
Select all images from database by emp_code (as you want all images of a particular user/emp).
select car_images from TableName where emp_code = $emp_code;
Now, by this you will get one or more rows.
So, add one by one images to array with using explode() function per row (i.e. if row has multiple image name with comma separated).
Use the array as per your choice of manipulation.
Below code will fetch the data from table and save images in array. For more details check the explode function.
$query = "select car_images from table_name where emp_code = 'emp_code'";
$result = mysqli_query($connection,$query);
$row = mysqli_fetch_assoc($result);
$images = $row['car_images'];
$images = explode(',',$images);
foreach($images AS $image){
echo '<img src="car_images/'.$emp_code.'/'.$image.'">';
}
You can use GROUP_CONCAT() function
SELECT GROUP_CONCAT(car_images) FROM TableName
You can use group by also with emp_code or brand_id or any other column whatever your business logic is met.
SELECT GROUP_CONCAT(car_images) FROM TableName GROUP BY emp_code
OR
SELECT GROUP_CONCAT(car_images) FROM TableName GROUP BY brand_id
<?php
$x=0;
$car_img =explode(",",$car_images);
foreach($car_img as $car_images{
$x+=1;0
?>
<?php echo '<img src="'."images/".$car_images.'" width="70" height="70" />';?>

SQL value won't change as image changes in dynamic Lightbox gallery?

I have tried many hours just to get this tiny piece of information to show, I need help before I decide to brake my laptop in two pieces.
I am trying to get an uploaded image to display a caption along with username (person who uploaded it) and date. These three values are stored in my database, the upload works fine. As I loop through the directory to display my images, I cannot get these values (passed as variables) to display correctly, rather the last upload input is the only one that displays for every image in my gallery.
I assume there is something wrong in my loop code and will post it here in hope that it is a simple overlooked fact.
//Open directory
$dir_handle = opendir($thumb_dir) or die('Error opening thumbnail directory.');
while ($file = readdir($dir_handle)) { //go through files
//if ($file == '.' || $file == '..') continue;
$file_parts = explode('.', $file); //split filename and put extensions in array
$ext = strtolower(array_pop($file_parts)); //last element file extension
//Filename w/o extension.
$title = implode('.', $file_parts); //only filename
$title = htmlspecialchars($title); //security measure
$dbconnect = mysqli_connect('localhost', 'peter', '1234', 'dt091g');
$query = 'SELECT username, date FROM image_info';
$result = mysqli_query($dbconnect, $query);
while ($row = mysqli_fetch_assoc($result)){
$username = $row['username'];
$date = $row['date'];
}
//add every image if good extension
if (in_array($ext, $allowed_exts)) {
echo '<a class="example-image-link"
href="'.$img_dir.$file.'"
data-lightbox="example-set"
data-title="'.$username.$date.'">
<img class="example-image" src="'.$thumb_dir.$file.'" alt="hello"/>
</a>';
$i++; //increment the image counter
}
}
closedir($dir_handle); ?>
I am assuming I must incorporate the unique ID somehow, and I have tried myself blind, but still end up with only the last value for any row of my db table.
Appreciate any kind of input, even if you're just writing to say 'Duh! You idiot'.
EDIT: Showing a record of image_info
$image_info = array( array('id' => '50','username' => 'Peter','date'
=> '05052015','filename' => '20140808_220541.jpg','mimetype' => 'image/jpeg','filesize' => '2404856','caption' => 'Norwegian
Mountains'));

Rename images in database to md5 but keep extensions

As the title says I'm wanting to change the image names stored in a database to md5 but keep the image extension, I had a go with the code below but it failed (probably due to the fact I haven't a clue what I'm doing) ...any ideas on how I could achieve my goal?
function get_file_extension($file_name) {
return substr(strrchr($file_name,'.'),1);
}
$query = "SELECT img FROM post";
$result = mysql_query($query);
while($row = mysql_fetch_array($result)) {
$name = substr($row['img'], -4, 4);
$ext = get_file_extension($row['img']);
$notmd5 = $row['img'];
$md5img = md5($name).'.'.$ext;
$q = "UPDATE post SET img='$md5img' WHERE img='{$notmd5}'";
$r = mysql_query($q) or die(mysql_error());
}
..........................................................
Update
Answer:
Rename files in dir/folder and db names at same time:
function get_file_extension($file_name) {
return substr(strrchr($file_name,'.'),1);
}
//path to directory to scan
$directory = "thumbs/";
$directory2 = "md5/";
//get all image files with a .jpg extension.
$images = glob($directory . "*.*");
//print each file name
foreach($images as $image)
{
$imag = str_replace($directory, '', $image);
$ex = get_file_extension($imag);
$new = md5($imag).'.'.$ex;
rename($image, $directory2.$new);
$q = "UPDATE post SET img='$new' WHERE img='{$imag}'";
$r = mysql_query($q) or die(mysql_error());
}
When I originally asked my question I had already renamed the images in dir/folder but I had a backup of them so mixed the to jobs together and got my goal :)
First off, I'd recommend a batch update like this just be done with pure SQL, especially if the business logic is as simple as this, it can all be done natively in MySQL for sure.
Anyway.., one thing that pops out is the substr call to get the $name of the file, it's hardcoded to get only 4 characters and it's actually getting the extension not the name.
Try this instead:
$ext = get_file_extension($row['img']); // get ext first
// use length of $row['img'] - length of file extension to extract name
substr($row['img'], 0, strlen($row['img']) - strlen($ext) - 1);
Just do it in pure SQL:
UPDATE post SET img = CONCAT_WS('.',
MD5(TRIM(TRAILING CONCAT('.', SUBSTRING_INDEX(img, '.', -1)) FROM img)),
SUBSTRING_INDEX(img, '.', -1)
)

Delete files that are not in my database

I'm trying to delete photos from a folder, which is called, "photos", that are NOT currently in my database. (These are all photos that have stacked up as I've been building the website and testing it and such, so now it's time to take the site live and I don't want all this waste in it)
I have three tables with photo information in them, and a number of columns throughout. Below is a mockup query of about what I THINK it should look like.
SELECT left_image, right_image, photo1, photo2, photo3, photo4, home_photo
FROM about_photos, facilities, home
left_image and right_image go with about_photos.
photo1, photo2, photo3 and photo4 go with facilities.
home_photo goes with home.
Also, I need to use a wildcard for the end of the photo, because the files have thumbnails, so for instance the original photo would be called, abcimage.jpg but there would be abcimage.jpg, abcimage_medium.jpg, abcimage_thumb.jpg also in the database I only store, photos/abcimage and add the rest of the filename depending on where it goes.
$directory = "../path/to/photos_directory/";
//get all image files with a .jpg extension.
$images = glob($directory . "*.jpg");
foreach($images as $image)
{
$name = explode('_',$image);
$name = 'photos/' . $name[0];
$sql = mysql_query("SELECT id FROM table WHERE photo1='$name' OR photo2='$name'");
if(mysql_num_rows($sql) == 0)
unlink($directory . $image);
}
You have two options:
One:
With an SQL query, get a complete list of all the photos referenced in your database
iterate through the files in your directory
if the file is an image AND it is not in your list, delete the file.
Two:
iterate through the files in your directory
if the file is an image
query the database for that filename
if the response is empty, delete the file
The exact SQL query depends on your table structure, which you have not provided.
The best option depends mostly on scale. If there are lots of images in the database, then the first option involves having a very large list in memory. However the second version involves many more database queries. So it's a tradeoff.
There are more sophisticated options involving caching and pre-emptive queries, but I imagine you don't want to go that deep yet.
Something like the following. I've also got original files in the folder and I limit to 500 deletions at a time. Tweak as you need. Hope it saves somebody time...
<?php
require 'session.php';
require 'settings.php';
/* Execute the query. */
$DBH = new PDO($mssql_driver.'='.$mssql_server.';'.$mssql_dbkey.'='.$mssql_database, $mssql_username, $mssql_password);
$DBH->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
$tsql = 'select * from ProductImage';
$PRE = $DBH->prepare($tsql);
$PRE->execute();
$pictures =$PRE->fetchAll(PDO::FETCH_ASSOC);
$directory = $_SERVER["DOCUMENT_ROOT"]."\..\..\products\pictures/";
//get all image files with a .jpg extension.
$images = glob($directory . "*.jpg");
$counter =0;
foreach($images as $image)
{
$name = explode('pictures/',$image);
$name = $name[1];
$foundImage = false;
print "checking: ".$name;
foreach ($pictures as $picture){
$original_file = explode('.', $picture['Image_Big']);
$original_file = $original_file[0].'-original.'.$original_file[1];
if ( ($picture['Image_Small'] == $name)|| ($picture['Image_Big'] == $name) || ( $original_file == $name) || ($picture['Image_Thumb'] == $name) || ($picture['Image_PriceList'] == $name)){
$foundImage = true;
break;
}
}
if (!$foundImage) {
unlink($directory . $name);
print "....deleting";
$counter += 1;
}
print "<br />";
if ($counter> 500){
exit;
}
}
?>

How to insert these values correctly in the database

Below is part of the code where it uploads a file (fileImage) into a folder (ImageFiles). But what I want to also do is INSERT the file location (The location the file is uploaded into) into the database using INSERT VALUES code. I want the file location to be inserted into the "ImageFile" field and for the "ImageId" I want it to display the string "IMG" and then include a number after the string. For Example:
In my database table if it reads like this:
ImageId ImageFile
IMG1 ImageFiles/penguins.png
IMG2 ImageFiles/desert.png
IMG3 ImageFiles/jellyfish.jpg
Then if I upload the file from my computer 'tulips.png' into the ImageFiles folder, then in the database it should insert the values like this below:
ImageId ImageFile
IMG4 ImageFiles/tulips.png
But how can this be coded? Below is my code at the moment which uploads the file successfully and contains only partial coding of the INSERT VALUES:
move_uploaded_file($_FILES["fileImage"]["tmp_name"],
"ImageFiles/" . $_FILES["fileImage"]["name"]);
$result = 1;
$imagesql = "INSERT INTO Image (ImageId, ImageFile)
VALUES ("");
mysql_query($imagesql);
If you use PHPs PDO object it would simplify your code and make it more safe at the same time (by using prepared statements).
Here's an example of how you would do that:
Firstly, store your ID as an AUTO_INCREMENT-ed INT rather than "IMG#" as this would make things easier (you wouldn't need to INSERT the ID value then)
DROP TABLE IF EXISTS tbl_img_store;
CREATE TABLE tbl_img_store(
id INT NOT NULL AUTO_INCREMENT,
PRIMARY KEY(id),
filename VARCHAR(25) --increase this if you think you need to
) ENGINE=InnoDB;
Also, create a table to store configuration settings to make your database more efficient:
DROP TABLE IF EXISTS tbl_img_config;
CREATE TABLE tbl_img_config(
img_path VARCHAR(50)
);
INSERT INTO tbl_img_config (img_path) VALUES ("http://img.mysite.com/?i=");
Now back to PHP, you can quickly insert a load of images like this:
# Create a DB connection
$db = new PDO("mysql:host=X.X.X.X;dbname=mydb", $user, $pass);
# Compile an array of image paths
$img1path = "img1.png";
$img2path = "img2.png";
$img3path = "img3.png";
$images = array($img1path, $img2path, $img3path);
# Create a query to insert the paths to the db
$sql = "INSERT INTO tbl_img_store (filename) VALUES (?),(?),(?);";
$query = $db->prepare($sql);
$query->execute($images);
# Check rows affected
$rows = $query->rowCount();
echo "$rows images were saved.";
You should use an auto incremented id for identifying images instead of using strings for this.
This would ease up the process for you as you would only have to insert a single fields and the autoi ncremented fields updates automatically.
$imagesql = "INSERT INTO Image (ImageFile) VALUES ('ImageFiles/".mysql_real_escape_string($_FILES['fileImage']['name'])."')";
ImageId should then be of type INT as PRIMARY KEY with AUTO INCREMENT instead. That's also a good way to design your tables.
You need to add the values to the query like this
$imagesql = "INSERT INTO Image (ImageId, ImageFile)
VALUES ('$imageName','$imageFile');";
But first make sure you escape the values correctly to avoid any problems. Also note that it's not recommended to use the mysql_ functions any more. Instead use mysqli_ equivalents or better still PDO (with PDO it will automatically handle the DB escaping for you.
You can use MySql Auto increment .. you don't need to worry about IMG IMG2 ... etc
See : http://dev.mysql.com/doc/refman/5.5/en/example-auto-increment.html
Example:
Assumption : ImageId is an auto increment field
http://dev.mysql.com/doc/refman/5.5/en/example-auto-increment.html
$tmpName = $_FILES ["fileImage"] ["tmp_name"];
$fileName = $_FILES ["fileImage"] ["tmp_name"];
move_uploaded_file ( $tmpName, $fileName );
$sql = "INSERT INTO Image (ImageId, ImageFile) VALUES (NULL,'%s');";
mysql_query ( sprintf ( $sql, mysql_real_escape_string ( $fileName ) ) );
When you want to get your images
$sql = "SELECT ImageId, ImageFile FROM Image";
$result = mysql_query ( $sql );
while ( $row = mysql_fetch_assoc ( $result ) ) {
echo "IMG", $row ["ImageId"], " = ", 'ImageFiles/' , $row ["ImageFile"], PHP_EOL;
}
Reason Why you should use this
A. IMG and ImageFiles/ are constant saving them several times is not efficient
B. integer based id would also faster than varchar and performs better on `JOIN
C. To get IMGX where X is an increment value would involve multiple SQL calls .. and not efficient
This is what I do. For an answer to your question, look near the end of the second file, for the mysql_query for SELECT LAST_INSERT_ID(). Note that I don't INSERT an id but let the database auto_increment.
The image is uploaded through upload.php, part of which looks like this:
<form>
<?php
session_start();
if (isset($error["image"])) echo '<span class="error">'.$error["image"].'</span>'; else echo 'Select an image<span class="required"> *</span>';
if ($imgVars["is_image"] == "J") {
echo '
<input type="hidden" name="image_url" value="'.$imgVars["image_url"].'">
<input type="hidden" name="image_type" value="'.$imgVars["image_type"].'">
<input type="hidden" name="is_image" value="J">
<img src="'.$imgVars["image_url"].'" width="224" height="168" alt="Image">
<p>Change image?</p>';
?>
<input type="file" name="image">
<input type="submit" name="upload" value="Upload" title="Upload your image">
</form>
Then the uploaded file is processed through process.php, part of which looks like this:
<?php
session_start();
if (!session_is_registered("error"))
session_register("error");
$error = array();
if (!session_is_registered("imgVars"))
session_register("imgVars");
foreach($_POST as $varname => $value)
$imgVars[$varname] = trim(EscapeShellCmd(stripslashes($value)));
$imgVars = array();
if ($imgVars["is_image"] != 'J') {
$imgVars["is_image"] = 'N';
if ($_FILES["image"]["size"] > 0) {
$size = GetImageSize($_FILES["image"]["tmp_name"]);
$width = $size[0];
$height = $size[1];
if(($width != 224) || ($height != 168)) {
$error["image"] = 'Image dimensions must be exactly 224 x 168 pixel!';
$imgVars["is_image"] = "N";
}
preg_match("/(\.\w+)$/",
$_FILES["image"]["name"],$match);
$imagetype = $match[1];
if (!in_array(strtolower($imagetype), array(".jpg",".jpeg",".gif",".png"))) {
$error["image"] = 'You may upload only images of type JPEG, GIF and PNG!';
$imgVars["is_image"] = "N";
}
if ($imgVars["is_image"] == "J") {
$filename = time().$imagetype;
copy($_FILES["image"]["tmp_name"], "img/".$filename);
$imgVars["image_url"] = "img/".$filename;
$imgVars["image_type"] = $imagetype;
}
} else {
$error["image"] = 'Please upload an image!';
}
}
if (count($error))
{
header('Location: upload.php');
exit();
}
// connect to database
$query = "INSERT INTO images SET image_url = '" . $imgVars["image_url"] . "';
if (!($result = # mysql_query ($query, $connection)))
die("Your mysql error routine here.");
$rs = mysql_query("SELECT LAST_INSERT_ID()", $connection);
$lid = mysql_fetch_row($rs);
$image_id = $lid[0];
if ($imgVars["is_image"] == 'J') {
rename ($imgVars["image_url"], "img/".$image_id.$imgVars["image_type"]);
$query = "UPDATE images SET image_url = 'img/".$image_id.$imgVars["image_type"]."' WHERE image_id = '".$image_id."'";
if (!(# mysql_query ($query, $connection)))
die("Your mysql error routine here.");
}
session_unregister("formVars");
session_unregister("fehler");
header('Location: danke.php');
exit();
?>
There might be typos or omissions in this code, because I translated and trimmed it from my original file without testing.
First of all : ALWAYS use mysql_real_escape_string when inserting values in the db.
Then :
$query = "INSERT INTO `Image` (`ImageId`, `ImageFile`)
VALUES ('".mysql_real_escape_string($_FILES["fileImage"]["tmp_name"])."','".
mysql_real_escape_string($_FILES["fileImage"]["name"])."'
);";

Categories