Link to home
Start Free TrialLog in
Avatar of Žan Anđić
Žan AnđićFlag for Bosnia and Herzegovina

asked on

Multiple upload files with PHP and MySQL, save data and showing them

Hi,

I have SQL table like this:
id | name | surname | dateofbirth | address | contact | dateofentrie | attachement1 | attachement2 | otherattachements

So I need in one form to add 2 files in 2 fields with input type="file", and one field is for upload multiple files.

<?php
require ('functions.php');

if (isset($_POST['submit'])){
	$name=$_POST['name'];
	$surname=$_POST['surname'];
	$dateofbirth=$_POST['dateofbirth'];
	$address=$_POST['address'];
	$contact=$_POST['contact'];
	$dateofentrie=$_POST['dateofentrie'];
        $attachement1=$_FILES['attachement1'];
	  $url = uploadAttachement1($attachement1);
        $attachement2=$_FILES['attachement2'];
	  $url2 = uploadAttachement2($attachement2);

$adduser=addNewUser($name,$surname,$dateofbirth,$address,$contact,$dateofentrie,$attachement1,$attachement2,$otherattachements);
	if ($addNewUser) {
		header ('Location: users_list.php');
	}
	else {
		echo "Error";
	}
	}
?>

<p><b>Name:</b> 
<input type="text" class="form-control" name="name"></p>
<p><b>Surname:</b> 
<input type="text" class="form-control" name="surname"></p>
<p><b>Date of birth:</b> 
<input type="date" class="form-control" name="dateofbirth"></p>
<p><b>Address:</b> 
<input type="text" class="form-control" name="address"></p>
<p><b>Contact:</b> 
<input type="text" class="form-control" name="contact"></p>
<p><b>Date of entrie:</b> 
<input type="text" class="form-control" name="dateofentrie" value="<?php echo date('d.m.Y'); ?>" readonly></p>
<p><b>Attachement1 (example: CV):</b> 
<input type="file" class="form-control" name="attachement1"></p>
<p><b>Attachement2 (example: References):</b> 
<input type="file" class="form-control" name="attachement2"></p>
<p><b>Other attachements:(example: certificates etc...)</b>
<input type="file" multiple class="form-control" name="otherattachements" ></p>

Open in new window


Maybe is good to automatic rename files, for example, attachement1: name_surname_cv_dateofentrie.pdf

or if is possible to automatically make new directory if not exist which is named from inputs in fields "name" and "surname".

So I have list of users, and every user is clickable, when click on name, opening user details. In user details I need to show all informations from columns in SQL table and I need to show: example: CV - name_surname_cv_dateofentrie.pdf which is clickable and opening that file. And where is Other attachements I need to show list of files, all files need to be clickable.

I know how to make that for no multiple files, but didnt sure about rename, and moving and creating directories. I am searching for example like this on net, and tutorial, but no successfull.

I have file with functions named: functions.php

function uploadAttachement1($attachement1) {
	if($attachement1){
		$upload=move_uploaded_file($attachement1['tmp_name'],'documents/'.$attachement1['name']);
		if($upload) {
			return "documents/".$attachement1['name'];
		}
		else {
			return null;
		}
	}
}

function uploadAttachement2($attachement2) {
	if($attachement2){
		$upload=move_uploaded_file($attachement2['tmp_name'],'documents/'.$attachement2['name']);
		if($upload) {
			return "documents/".$attachement2['name'];
		}
		else {
			return null;
		}
	}
}

Open in new window



Thank you
Avatar of Julian Hansen
Julian Hansen
Flag of South Africa image

Maybe is good to automatic rename files, for example, attachement1: name_surname_cv_dateofentrie.pdf
Definitely, otherwise you run the risk of collisions - two users uploading using the same filename.
or if is possible to automatically make new directory if not exist which is named from inputs in fields "name" and "surname".
And if you have two users with the same name and surname - again you have a collision.

What I would do is rename the file using an ID / GUID / random name or similar. Store this in the database. At the same time also store the original filename - the one that was used by user when they uploaded. I would also keep the files in a flat space.

If you need to download the file you get the id from the database and in the download code you create (using headers) the filename you want it to download as again using the original name you saved in the database.

This option allows you the most flexibility.

Now to the other files. This points to a potentially bad DB design. A better option might be to rationalise your DB and create a files table that you then populate with files linked to the parent user on the user id. This will require a JOIN to retrieve the data but it will mean you can handle as many files per user as required.

If you want / have to store in a single record then I would consider creating an array of objects that store the file details and then JSON encode (or serialize - I prefer JSON) and store the JSON string in the other attachments field.

When you display the user record you simply json_decode() the string and use the decoded data to render the file list.
Avatar of Žan Anđić

ASKER

Thank you for answer,

For make new directories I can maybe add column n DB identification number from personal card (jmbg) and when making directory use $name,$surname and $jmbg
I can make new table in DB, named files, and make columns. What is the best way? how to table where is files with user details?
How to do that with JSON?
You can use a unique user id to create a directory if you wish.

To create a separate table for your files I would do this
create table `attachments`( 
   `id` int NOT NULL AUTO_INCREMENT , 
   `date` timestamp DEFAULT CURRENT_TIMESTAMP , 
   `usreid` int , 
   `path` varchar(255) , 
   `original_filename` varchar(255) , 
   PRIMARY KEY (`id`)
 )

Open in new window

(the timestamp is optional - I added it in case upload date is important)
For each attachment you would add a record to this table linked on userid
Path is the name of the file (with directory) on disk
Original filename is the name the user used when they uploaded the file.

You would then retrieve your data like so

SELECT * FROM userTable u LEFT JOIN attachments a ON u.id = a.userid

Open in new window


The first record gives you your standard user data which you use to populate the profile as well as the first attachment. You then iterate over the remaining records to get the rest of the attachments.
// Assume $userid holds id of user you want to view
$query = "SELECT * FROM userTable u LEFT JOIN attachments a ON u.id = a.userid WHERE u.id = '{$userid}'";
$result = $mysqli->query($query);
if (!$result) {
  // handle error here
}
// Get first record for user data and first attachment
$row = $result->fetch_object();
// Populate user data here and first attachment
while ($row = $result->fetch_object()) {
   // complete rest of attachment list here
}

Open in new window

Thank you

What is solution without creating table in database for files?

After uploading show array with filenames? How ?
First of all change the name on your <input> to an array like this
<input type="file" multiple class="form-control" name="otherattachements[]" >

Open in new window

You could then use something like this to generate a string containing the data for the additional attachments
$otherattachment = isset($_FILES['otherattachements']) ? $_FILES['otherattachements'] : array('name' => array());
$attachments_array= array();
foreach($otherattachment['name'] as $key => $attachment) {
   $attachment = new stdClass;
   $attachment->name = $attachment;
   $savepath = getUserSavePath($userid);
   // Save the file to the right location
   move_uploaded_file($otherattachment['tmp_name'][$key], $savepath);
   $attachment->path = $savepath;
   $attachments_array[] = $attachment;
}

$dbattachments= json_encode($attachments_array);
// Add $dbattachments to your query and save in the database

function getUserSavePath($userid) {
   // Implement your unique path creation here
}

Open in new window

Does that can all be in one function named: uploadFiles

so
function uploadFiles ($otherattachment){
$otherattachment = isset($_FILES['otherattachements']) ? $_FILES['otherattachements'] : array('name' => array());
$attachments_array= array();
foreach($otherattachment['name'] as $key => $attachment) {
   $attachment = new stdClass;
   $attachment->name = $attachment;
   $savepath = getUserSavePath($userid);
   // Save the file to the right location
   move_uploaded_file($otherattachment['tmp_name'][$key], $savepath);
   $attachment->path = $savepath;
   $attachments_array[] = $attachment;
} 
$dbattachments= json_encode($attachments_array);
if ($dbattachements) {
return "mypath/".$dbattachements; 
}
else {
return null; 
}
}

Open in new window

You can put it wherever you want. The code is sample code only you need to adapt it to your situation.
Tryed, upload just one file :(
You are going to have to give me more than that.
I am attached to you my index.php file, and functions.php file where is function.

in index.php file on line 388 is input field and on lines 97 is final function for add entry in database, and on lines 93 and 92 are variables for documents upload (multiple).

In functions file

on the end you can see.
index.php
funkcije.php
That function worked for me - uploaded 3 files and all were copied to the target folder.

Your code could be structured a bit better.

1. I would move the form processing into its own PHP file. This file loads the form with a require statement
2. Format your code so that it is neater - it is very difficult to debug code that is all over the place
3. This call
$dodajunosbaza=dodajUnosBaza($ime,

Open in new window

Is very messy - consider using an object or an array to pass your variables rather than an overlong parameter list.

If you want help on this you are going to have to provide more information.

Do you get any errors.
What happens when you run the code - what do you expect what are your getting.
When I run code - uploaded success, and I get echo information: filename.txt is uploaded, filename2.txt is upladed... Now I want to get filenames and insert into variable which is: putanja_files=unosFajl ...

putanja_files is under dodajunosbaza=dodajUnosBaza($ime,$prezime$.......$putanja_files)


In above variables you can see putanja_rjesenje and putanja_anamneza, and when I click submit button, I in database write filename with full path, from return in function uploadRjesenje and uploadAnamneze. I want the same thing with uploadFajl and putanja_files.
What I am hearing is you want to return the filenames from the function that saves them?

Create an array - store the paths in the array and return the array.

I am not 100% clear on what you are asking so I can't be specific on how to do this.
Yes that is what I want,

how to create that array? how that needs to look like?
ASKER CERTIFIED SOLUTION
Avatar of Julian Hansen
Julian Hansen
Flag of South Africa image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Yes, that works, thank youuu so much

I get text in my sql field:

["dokumenti/ostali/fluid.txt","dokumenti/ostali/home_page.txt","dokumenti/ostali/kategorija korisnika.txt","dokumenti/ostali/korisnik.png"]

Open in new window


Is there way to show that without brackets and quotes and commas, something like this:

dokumenti/ostali/fluid.txt
dokumenti/ostali/home_page.txt
dokumenti/ostali/kategorijakorisnika.txt
dokumenti/ostali/korisnik.png

To put <br> and make links to paths?

And one question more, is there way to use mkdir from variables $name, $surname, $number (number - unique number in database for every user from personal card). I am trying something before, but I have trouble with special characters, if name and surname have čšćžđ, file name be like example:

This is how need to be: Žan_Anđić_178000.doc
I get like this: %$'/an_An%/*-%i/%'_17800.doc

Something with utf8 encode?
You can but that defeats the purpose. You want to be able to access those documents - you are storing multiple document paths in a single list.

I used json_encode so that you can get the array back again when you need those paths
$paths = json_decode($row['extra_files_column_name_here']);
// Now paths is an array of paths.

Open in new window


If you do it the other way you will have to still explode (or similar) the data to get the paths back.

JSON is the easiest way of doing this.
You want to be able to access those documents - you are storing multiple document paths in a single list.

Yes that is what I need. Exactly.  

I will try to do that, now.
    // IF SUCCESSFUL THEN ADD TO RETURN ARRAY
         $files[] = '<a href="'.$targetpath.'">'.$targetpath.'</a><br>';
       }
     }
   }

   // RETURN ARRAY OF PATHS TO SUCCESSFUL FILE UPLOADS
   return implode(' ',$files);
 }

Open in new window


I am try this, and get all what I want, but with quotes on begin and on the end.

"<a href=dokumenti/ostali/korisnik.png>dokumenti/ostali/korisnik.png</a><br> <a href=dokumenti/ostali/peel_stick2.png>dokumenti/ostali/peel_stick2.png</a><br>"

Open in new window


Need to remove (")
Let me explain why I would not do it this way.

When you store the actual format of the link in the database it locks you into that format. If you decide to change the format in the future - even by 1 character you have to change every record in your database - not good practice.

I also would stay with JSON over implode as it is a standard - it is the same amount of effort to use as explode / implode (if not less) and it is a widely supported and understood format.

As to the issue of the quotes - I don't know what quotes you are referring to nor where you get your data from - the implode should not be causing this - whatever it is - it is not in the code you have shown.
"<a href=dokumenti/ostali/korisnik.png>dokumenti/ostali/korisnik.png</a><br> <a href=dokumenti/ostali/peel_stick2.png>dokumenti/ostali/peel_stick2.png</a><br>"
Are you referring to the double quotes around the above? If so - how are you outputting that string - I need to see all the code from the time you get it from the DB until you output it - what you have given me is simply not enough.
Thank you

I fix, put
$putanja_files=str_replace('"','',$red['prilog_ostali']);

Open in new window

Now showing good. This way is not useful if I need to change something in files, or upload more, or something, but when you adding new user in database, and upload files, once when uploaded no changes.

How to this files put in new directory if not exist, directory can be named just from $jmbg (id number), no need for name and surname?
This way is not useful if I need to change something in files, or upload more, or something
Which is why I would use JSON

Add to files
1. Get record from database
2. Get field from record - $row['otherattachements ']
3. Decode
$files = json_decode($row['otherattachements ']);
4. Add new file
$files[] = "Path/To/New/File.txt";
5. Encode
$otherattachments = json_encode($files);
6. Put back in the database
UPDATE [TABLENAME] SET otherattachments='{$otherattachments}' WHERE [FILTER TO FIND RECORD]

Open in new window


How to this files put in new directory if not exist, directory can be named just from $jmbg (id number), no need for name and surname?
I am not sure I understand - are you asking
1. How to make a directory
2. Find a name for a directory
3. How to save the files to a specified directory?
I need to save file in directory which will be created for everyuser with mkdir from variable $jmbg and after save get path like on this what we success finished. Just need to save files in new directory
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Works perfectly.

Thank you Julian.
Now I have just little trouble with special characters when uploading file, making directory and new file name.

I need to replace ćčšđž characters with: ccsdz

I try with str_replace but not successful

EDIT
Successfull
I put this and now works all well
$characters= array("ć", "č", "š", "ž", "đ", "Ć", "Č", "Š", "Ž", "Đ");
	$replacechar= array("c", "c", "s", "z", "d", "C", "C", "S", "Z", "D");
	$name=str_replace($characters,$replacechar,$name);

Open in new window

Thank you Julian Hansen for your time and help :)
You are welcome.