php, upload multiple files from multiple input - php

I have a form with multiple rows (rows from SQL, iterated and generated the form).
Each of those rows has a multiple file input field (the user can upload 0, 1 or multiple in each input).
Files are being uploaded correctly, with correctly assigned new file names (file names are generated based on each row SQL ID).
Then after user click the SUBMIT, the file names are added to a column in SQL table.
The form can generate 0, 1 ... 100 rows, so to prevent the php iterating through all those 100s rows, and executing an UPDATE or rows where it is not needed, I only execute the UPDATE on rows that the user has touched.
My problem is when I upload a single or multiple file on a singular file input field (a row), then everything works as expected.
However, when I try to upload 1 or more files in separate file inputs fields, then something strange happens in SQL, the files upload to the server are all OK, but database goes weird.
The first input (row) will have correct number of files with correct names, as desired.
Every next input (row, in the database after the UPDATE) will have the all the file names from all previous inputs, plus the ones that were uploaded for the specific input... if that makes sense... Here illustration:
Input 1: input1file1.jpg, input1file2.jpg
Input 2: input1file1.jpg, input1file2.jpg, input2file1.jpg
Because each input field can take multiple files, so the input name is already an array name='attachment[]'.
To distinguish between those input fields, I add row ID to file name.
Here is my code, I cannot work out what is causing it?
Form:
<form enctype="multipart/form-data" method="post">
...
php iteration:
<div>
<input class="hasChanged" name="attachments'.$row['pk'].'[]" type="file" multiple>
<input value="'.$row['existing_attachments'].'" id="updateAttachmentValue'.$row['pk'].'" name="existingAttachments'.$row['pk'].'">
</div>
...
</form>
PHP:
//iterate
foreach($_POST['foo_field'] as $key => $n){
if(in_array($upl[$key], $touched_rows)){
$aID = $upl[$key];
$prevAttachments = (empty($_POST['existingAttachments'.$aID]) || $_POST['existingAttachments'.$aID]=='|') ? NULL : $_POST['existingAttachments'.$aID];
$attachments = NULL;
if(count($_FILES['attachments'.$aID]['name']) > 0){
if(!empty($_FILES['attachments'.$aID])){
for($i=0; $i<count($_FILES['attachments'.$aID]['name']); $i++){//Loop through each file
$tmpFilePath = $_FILES['attachments'.$aID]['tmp_name'][$i];//Get the temp file path
if($tmpFilePath != ''){//Make sure we have a filepath
$shortname = 'AP-'.$aID.'-'.$_FILES['attachments'.$aID]['name'][$i];//save the filename
$filePath = $attachmentDirectory.'\AP-'.$aID.'-'.$_FILES['attachments'.$aID]['name'][$i];//save the url and the file
if(move_uploaded_file($tmpFilePath, $filePath)){//Upload the file into the correct dir
$files[] = $shortname;
}
$attachments = implode('|',$files);
}
}
}
}
$prevAttachments = !empty($attachments) ? $attachments.'|'.$prevAttachments : $prevAttachments;
try{
$stmt = $conn->prepare("EXEC [name].[dbo].[table] :p1,:p2");
$stmt->bindParam(':p1', $upl[$key], PDO::PARAM_INT);
$stmt->bindParam(':p2', $prevAttachments, PDO::PARAM_STR);
$stmt->execute();
}catch(PDOException $e){ echo 'ERROR: ' . $e->getMessage();}
}
}

In your code you never set or reset $files so that's why the value contains all previous files.
You should set $files = array(); at the beginning of each "row" to ensure $files only contains values for the specific row.

Related

php - compare between the indexes of one array and the values of another array

I have a project in which I should upload multiple images to the web page with image removal option.
So it's obvious when I upload images using input with name of images and remove some uploaded images the removed images don't be removed from the input and when I submit the form all images are inserted into database even removed images ..
Now when ever I remove an image from web page I append a hidden input with name of deletedImg[] inside my form : this input will have the index of removed image (eg. first image removed then the input with name deletedImg[] will have the value of 0,second image removed then another input with name deletedImg[] will have the value of 1 .. and so on)
These values are the indexes of removed images and I want to ignore them when I upload the images when the form is submitted .. how can I achieve this?
if(isset($_POST['post']))
{
$deleted = $_POST['deletedImg']; //This is the array containing the deleted image indexes
foreach($_FILES['images']['name'] as $key=>$val)
{
$nameOfImage = basename($_FILES['images']['name'][$key]);
$avatarTempName = $_FILES['images']['tmp_name'][$key];
// List of allowed image extensions
$avatarAllowedExtension = array("jpeg", "jpg", "png", "gif");
// Get avatar extension
$avatarExtension = strtolower(end(explode('.', $nameOfImage)));
if(in_array($avatarExtension, $avatarAllowedExtension))
{
$postImage = rand(0, 10000000000) . '_' . $nameOfImage;
// Move image into Covers folder
move_uploaded_file($avatarTempName, "Uploads\Posts\\" . $postImage);
// Insert image into database
$stmt = $con->prepare("insert into postImages (ID , userId , postID , postImg) values (DEFAULT , :userId, (select max(ID)from post) , :postImg)");
$stmt-> execute(array(
'userId' => $_SESSION['ID'],
'postImg' => $postImage
));
}
}
}
To get the values of this array you can use this:
$deleted = array_values($_POST['deletedImg']);
You then can use in_array($val, $deleted) to check of one of the posted imagename exists in the deleted array.

PHP - Check for distinct filename on file upload

I'm pretty new to PHP. I hate to have to ask questions, because I'm sure this is documented somewhere, but after looking for a while, I just cannot seem to put two and two together.
I have a program that will allow multiple images to be uploaded to an item within the database. Basically, for each item in the database, there might be multiple image uploads.
Example:
Item: Xbox 360
Images:
Xbox360.jpg
side.jpg
front.jpg
The image and item information is all stored in the database (MySQL), but the images are stored within the filesystem, and the database points to the URL of the image(s) in the filesystem.
The problem I'm having is that everything works as expected, except it allows duplicate image names to be written to the database. It doesn't allow duplicate images to be written to the filesystem, which I'm happy with. I want to make sure that the name of an image is only added once to the database. If the image name is a duplicate to another, it needs to not write to the database.
add_db.php:
$uniqueDir = uniqid();
$directory = "img/$uniqueDir/";
db_addItem($id_category, $name, $cost, $description, $qty, $directory); //Adds to the `items` table
foreach ($_FILES['i_file']['name'] as $filename) {
if ($filename != '' && $filename != 'No file chosen') {
//I think above is where I check for unique image names
$url = "img/$uniqueDir/$filename";
db_addImg($url, $filename); //Adds to the `img` table
$item_picsID = get_item_PicsID($filename, $url);
$itemID = get_itemID($directory);
db_insertImg($itemID, $item_picsID);
}
}
addFilesystem($directory); //Writes image(s) to filesystem
function db_addImg($url, $filename) {
include 'mysql_login_pdo.php';
// Create the SQL query
$query = "INSERT INTO img (`name`, `url`) VALUES(:filename, :url)";
$stmt = $db->prepare($query);
$stmt->execute(array(
':filename' => $filename,
':url' => $url
));
}
function db_insertImg($itemID, $item_picsID) {
include 'mysql_login_pdo.php';
// Create the SQL query
$query = "INSERT INTO `item_pics` (`item_id`, `img_id`) VALUES(:itemID, :item_picsID)";
$stmt = $db->prepare($query);
$stmt->execute(array(
':itemID' => $itemID,
':item_picsID' => $item_picsID
));
$db = null;
return;
}
Everything works, except it will write duplicate image names to the database. I want the image names to be distinct. I also don't want to rename the images (if possible).
You can define an UNIQUE index on the name column in img table, and then use slightly modified INSERT statement in your db_addImg function:
function db_addImg($url, $filename) {
//...
$query = "INSERT INGORE INTO img (`name`, `url`) VALUES(:filename, :url)";
//...
}
It will quietly cancel any insert where the is a UNIQUE key collision, which will end up in distinct filenames across your img table.
I would use a filename based on the primary key from the img table as you're guaranteed it's unique.
Otherwise, you'll need to guess a unique filename with some type of hashing and then check the file system. All of which can be expensive operations.
Looks like you are using PDO, so the static method lastInsertId will get the last insert id (primary key).
For example:
// after your insert to img
$filename = 'img' . $db->lastInsertId() . $extension;
This will require changing the img table slightly. But you're better off storing meta data (file type, size, etc) in this table as opposed to the file location (as that can change).
I think better to use hash value of your url as the primary key. Be cause string searching is much slower as int.

SELECT DISTINCT still showing duplicate result

I have a HTML select form filled by SQL Query using SELECT DISTINCT...
The idea is to not show duplicate values from database, and it's almost working, but in some case it's giving a problem. To fill the SQL columns I'm using a PHP reading a TXT file with delimiters and explode function. If I have in the TXT file 10 duplicate columns, on my HTML it shows 2, instead of only 1... And I note that 1 is with 9 of the entries from database, and the other one have 1 entry that is always the last line from TXT file.
Resuming: the last line of TXT file always duplicate on the HTML select form.
Checking the database, everything looks ok, I really don't know why it's duplicating always in the last one.
I told about the PHP that make the SQL entry because i'm not sure if the problem is in the PHP that contains the HTML select or in the PHP that fill the database... I believe that the problem is in the PHP with HTML select since I'm looking in the database and everything is ok. The SQL query in this php is like this:
<td class="formstyle"><select name="basenamelst" class="formstyle" id="basenamelst">
<option value="Any">Any</option>
<?
$sql = mysql_query("SELECT DISTINCT basename FROM dumpsbase where sold=0");
while($row = mysql_fetch_assoc($sql))
{
if($row['basename'] == "")
{
echo '<option value="'.htmlspecialchars($row['basename'], ENT_QUOTES, 'UTF-8').'">unknOwn</option>';
}
else
{
echo '<option value="'.htmlspecialchars($row['basename'], ENT_QUOTES, 'UTF-8').'">'.htmlspecialchars($row['basename'], ENT_QUOTES, 'UTF-8').'</option>';
}
}
?>
</select>
Remember: if I upload to database 10 duplicate columns, it shows 2 on select. One with 9 entries, and another with 1 entry (always the last line of my TXT file)...
Okay, many people told me to trim() the columns and it still showing duplicate... So I came to the conclusion that I have some issue while loading the TXT for database. Here is the code where I get the values to put on database:
$file = fopen($targetpath, "r") or exit("Unable to open uploaded file!");
while(!feof($file))
{
$line = fgets($file);
$details = explode(" | ", $line);
foreach($details as &$value) // clean each field
{
$value = mysql_real_escape_string($value);
if($value == "")
{
$value = "NONE";
}
}
unset($value);
mysql_query("INSERT INTO dumpsbase VALUES('NULL', '$details[0]', '$details[1]', '$details[2]', '$details[3]', '$details[4]', '0', '$price', 'NONE', now(), 'NONE', 'NONE')") or die ("Uploading Error!");
It sounds to me like the error is when you are populating the table from the file, and that one of the values is ending up subtly different to the others.
The fact that it's the last line that differs makes me wonder if there are newline characters being included in each value (except that last line).
If this is the case, you should be able to correct it by running trim() or similar in your DB.
[Edit] Ideally, you want to do this as early as possible, i.e. correct the data rather than remembering it's wrong when you access it. If you can't find why the initial import is messing it up, you could correct the data immediately afterwards with UPDATE dumpsbase SET basename = TRIM(basename)
Try changing your query to the following:
SELECT DISTINCT TRIM(basename) FROM dumpsbase WHERE sold=0
Hope this helps.

multiple file upload sql/php

i am trying to upload multiple files and then insert the files names in mysql db
my problem is with inserting the names it only store the last file name
for($i=0;$i<count($_FILES['file']['size']);$i++){
if(strstr($_FILES['file']['type'][$i], 'image')!==false){
$file = 'uploads/'.time().' - '.$_FILES['file']['name'][$i];
move_uploaded_file($_FILES['file']['tmp_name'][$i],$file);
$na=$_FILES['file']['name'][$i];
$sql="INSERT INTO img (img_name) VALUES ('$na');";
}
}
notice that all the files are uploaded successfully
for($i=0;$i<count($_FILES['file']['size']);$i++){
if(strstr($_FILES['file']['type'][$i], 'image')!==false){
$file = 'uploads/'.time().' - '.$_FILES['file']['name'][$i];
move_uploaded_file($_FILES['file']['tmp_name'][$i],$file);
$na=$_FILES['file']['name'][$i];
$sql="INSERT INTO img (img_name) VALUES ('$na');";
}
}
you are just creating a string and storing some value. you have not executed it ..
Say $str = "apple"; Its just a declaration. I presume you have executed the query after the loop. Say you have 10 files. loop gets executed 10 times and $na has the last filename which gets inserted.
Soln: move your execute query inside the for loop.
for($i=0;$i<count($_FILES['file']['size']);$i++){
if(strstr($_FILES['file']['type'][$i], 'image')!==false){
$file = 'uploads/'.time().' - '.$_FILES['file']['name'][$i];
move_uploaded_file($_FILES['file']['tmp_name'][$i],$file);
$na=$_FILES['file']['name'][$i];
$sql="INSERT INTO img (img_name) VALUES ('$na');";
mysql_query($con,$sql); // note: $con is your connection string
}
}

Need input on a dynamic query output script

I have a homepage that has a bunch of images as links to other pages that has info about that image.
Image Name: $varExampleNAME
Damage: $varExampleDMG
Health: $varExampleHP
Mana: $varExampleMP
So the only info that will change on this page will be the variables.
What I want is to run one query script so that depending on the $fileName of the $currentPage
it grabs that row from the table if the $fileName matches a certain row name.
This is the script to find out what my fileName is:
//include database connection file
include_once 'connect_to_db.php';
$currentFile = $_SERVER["SCRIPT_NAME"];
$img = array_pop(explode("/", $currentFile));
$fileName$ = basename($img, ".php").PHP_EOL;
I'm having problems with the actual query script. Can anyone shed some light on how this will be done?
My table name is image_Name
Columns include id, name, damage, health, mana.
You should design your tables in order to fit your needs, in this case to retrieve a row based on a parameter.
If the name field of the table is consistent with the script filenames, you should do [using PDO]:
// Create a connection handler - provide your credentials
$dbh = new PDO('mysql:host=localhost;dbname=yourDbNane','username','password');
// Prepare the query with a placeholder
$dbh->prepare('SELECT * FROM image_Name WHERE name = ?');
// Fill the placeholder with the filename
$dbh->execute( array($fileName) );
// Fetch the result, you are done!
$img = $dbh->fetch();

Categories