Reputation: 23
Even if I am not good in development, I am trying to create a form which allows to upload several photos to the server and text to the database.
For the text, no problem. To upload ONE photo too, that's doing it well.
What I can't do is upload SEVERAL photos in a single form submission. Should I use a while or for or foreach loop? If so, how do I retrieve the photos informations? I specify that I'm not trying to use the "Multiple" function. Even if the files are uploaded in the same form, the user must use separate "File upload" fields.
I specify that I want to rename the files during the upload. With the code below, the upload works but only the renaming of the first file works. The second (and surely the following ones too) are badly renamed. Example for the second:
78_One Plus_Nouveau test_FaceProduct_pic03.jpgpic04.jpg
I would to have some help to create a loop for upload images process and rename correctly the image files please ?
error_reporting(E_ALL);
// Then retrieve all the other information from the form:
$productname = isset($_POST['productname']) ? $_POST['productname'] : NULL;
$productbrand = isset($_POST['productbrand']) ? $_POST['productbrand'] : NULL;
$addername = isset($_POST['addername']) ? $_POST['addername'] : NULL;
$adderemail = isset($_POST['adderemail']) ? $_POST['adderemail'] : NULL;
// paramètres de connexion
$cbnserver = "xxxxxx";
$cbnuser = "xxxxxxxxx";
$cbnpass = "xxxxxxxxx";
$cbndbname = "xxxxxxxxxxxxx";
// Requête d'insertion dans la base
$dbco = new PDO("mysql:host=$cbnserver;dbname=$cbndbname", $cbnuser, $cbnpass);
$dbco->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$req = $dbco->prepare('INSERT INTO `cbnadd_newproduct` (productname, productbrand, addername, adder_email) VALUES(:productname,:productbrand,:addername,:adder_email)');
$req->execute(array(
'productname' => $productname,
'productbrand' => $productbrand,
'addername' => $addername,
'adder_email' => $adderemail
));
$lineid = $dbco->lastInsertId() ;
// Designate the directory where the images will be saved with this code:
$targetFA = "images/". $lineid ."_". $productbrand ."_". $productname ."_FaceProduct_";
$targetFA = $targetFA . basename( $_FILES['photoFA']['name']);
$targetNV = "images/". $lineid ."_". $productbrand ."_". $productname ."_FaceProduct_";
$targetNV = $targetFA . basename( $_FILES['photoNV']['name']);
// This writes the photo to the server
$namefileFA = basename( $_FILES['photoFA']['name']);
$namefileFA = $lineid ."_". $productbrand ."_". $productname ."_". $namefileFA;
$namefileNV = basename( $_FILES['photoFA']['name']);
$namefileNV = $lineid ."_". $productbrand ."_". $productname ."_". $namefileNV;
if(move_uploaded_file($_FILES['photoFA']['tmp_name'],$targetFA) & move_uploaded_file($_FILES['photoNV']['tmp_name'],$targetNV)) {
// This code tells you if it is all ok or not.
echo "<br><br>The file ". $namefileFA. " and has been uploaded, and your information has been added to the directory<br>";
echo "<br><br>The file ". $namefileNV. " has been uploaded, and your information has been added to the directory<br>";
} else {
echo "<br><br>Sorry, there was a problem uploading your file.";
}
Here the HTML code for the photo fields :
<form enctype="multipart/form-data" action="../add.php" method="POST">
<!--Product Name: --><input type="text" name="productname"><br>
<h3>Brand</h3>
<!--Brand: --><input type="text" name = "productbrand"><br>
Importer les photos du produit:
<label for="fileFA" class="label-file" style="cursor:pointer; color:#00b1ca; font-weight:bold;">Couverture/face du produit</label>
<input id="fileFA" class="input-file" type="file" name="photoFA" style="display: none;">
<!--<input type="file" name="photo"><br>-->
<label for="fileNV" class="label-file" style="cursor:pointer; color:#00b1ca; font-weight:bold;">Tableau nutritionnel du produit</label>
<input id="fileNV" class="input-file" type="file" name="photoNV" style="display: none;">
Your name: <input type="text" name = "addername"><br>
Adder email: <input type="text" name = "adderemail"><br>
<input type="submit" value="Add" class="centered">
</form>
Upvotes: 0
Views: 83
Reputation: 33813
I put this demo together that shows how you might use a different naming convention in the HTML and tie that in with an array when processing the uploads with PHP.
If you look at the form - particularly the file
inputs you will note a common name productimage
but written in array syntax like productimage[ KEY ]
- that allows access to KEY
in the PHP whilst in the loop as you will see in the processing portion below. This was written for mysqli
but will be straightforward to migrate to PDO.
There are plenty of comments throughout to help guide you - but you can test just by editing the db connection details and the $dir
variable.
<?php
error_reporting( E_ALL );
if( $_SERVER['REQUEST_METHOD']=='POST' ){
class PostException extends Exception {
public function __construct( $msg=null, $code=null ){
parent::__construct( $msg, $code );
}
public function geterror(){
return $this->getMessage();
}
}
try{
#look at the form - see how it is using this for image name
$field='productimage';
if( isset(
$_FILES[ $field ],
$_POST['productname'],
$_POST['productbrand'],
$_POST['addername'],
$_POST['adder_email']
) ){
$errors=array();
$uploads=array();
$files=array();
$lineid=false;
$dbstatus=false;
#################################
# edit this as appropriate...
$dir=__DIR__ . '/images/uploads';
# the names of the various fields in the form - not images
$args=array(
'productname',
'productbrand',
'addername',
'adder_email'
);
/*
loop through the `$args` array - if a field in the FORM
is not set or empty throw & catch a custom exception -
the errors will be displayed later.
If no errors, generate the variables based upon the name of
the field using variable variables.
*/
foreach( $args as $fieldname ){
try{
if( !isset( $_POST[ $fieldname ] ) or empty( $_POST[ $fieldname ] ) ){
throw new PostException( sprintf( 'Missing data: The field "%s" is required.', $fieldname ) );
} else {
${$fieldname}=$_POST[ $fieldname ];
}
}catch( PostException $e ){
$errors[]=$e->geterror();
continue;
}
}
if( empty( $errors ) ){
# -------------------------------------------------
# ignore the fact that this is a mysqli connection
# the same methodology will work with PDO so you
# will need to use your own PDO connection
# OR
# edit the connection details below to suit
# -------------------------------------------------
$args=array(
'host' => 'localhost',
'user' => 'root',
'pwd' => 'xxx',
'db' => 'xxx'
);
mysqli_report( MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT );
$db=new mysqli( ...array_values( $args ) );
$db->set_charset('utf8');
$db->begin_transaction();
/*
create table `cbnadd_newproduct` (
`id` int(10) unsigned not null auto_increment,
`productname` varchar(50) null default null,
`productbrand` varchar(50) null default null,
`addername` varchar(50) null default null,
`adder_email` varchar(50) null default null,
primary key (`id`)
)
collate='utf8mb4_general_ci'
engine=innodb;
+--------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| productname | varchar(50) | YES | | NULL | |
| productbrand | varchar(50) | YES | | NULL | |
| addername | varchar(50) | YES | | NULL | |
| adder_email | varchar(50) | YES | | NULL | |
+--------------+------------------+------+-----+---------+----------------+
*/
#create the basic sql and prepared statement
$sql='insert into `cbnadd_newproduct`
( `productname`, `productbrand`, `addername`, `adder_email` )
values
( ?,?,?,? )';
$stmt=$db->prepare( $sql );
/* bind params and execute */
$stmt->bind_param('ssss', $productname, $productbrand, $addername, $adder_email );
$dbstatus=$stmt->execute();
/* get the ID of the last inserted record */
$lineid=$db->insert_id;
$stmt->close();
/*
create table `cbnadd_productimages` (
`id` int(10) unsigned not null auto_increment,
`lineid` int(10) unsigned not null,
`image` varchar(128) not null,
primary key (`id`),
index `lineid` (`lineid`)
)
collate='utf8mb4_general_ci'
engine=innodb;
+--------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| lineid | int(10) unsigned | NO | MUL | NULL | |
| image | varchar(128) | NO | | NULL | |
+--------+------------------+------+-----+---------+----------------+
*/
/*
It would be usual to record the names / paths of images
that you upload so I created a new table for that purpose
*/
# insert records for new images to other table.
$sql='insert into `cbnadd_productimages` (`lineid`,`image`) values (?,?)';
$stmt=$db->prepare( $sql );
$stmt->bind_param('is', $lineid, $targetname );
/*
Process the file uploads - using the Array syntax
means you can easily loop through all the files &
rename and log to db.
*/
$obj=$_FILES[ $field ];
foreach( $obj['name'] as $index => $void ){
$name=$obj['name'][ $index ];
$tmp=$obj['tmp_name'][ $index ];
# ensure we don't process non-existant files
if( !empty( $tmp ) ){
# new image name format "id_brand_product_category_filename.ext"
$targetname=sprintf('%d_%s_%s_%s_%s', $lineid, $productbrand, $productname, $index, $name );
# full path for the image to be saved to
$targetpath=sprintf('%s/%s', $dir, $targetname );
# move the file
$status=move_uploaded_file( $tmp, $targetpath );
# upload the output variable
$uploads[]=$status ? sprintf('The file "%s" has been uploaded OK.<br />Information has been added to the directory: %s', $targetname, ( $dbstatus ? 'True' : 'False' ) ) : sprintf('There was a problem saving "%s".<br />Information logged to db: %s ',$targetname, ( $dbstatus ? 'True' : 'False' ) );
# maintain a list of files to be used if db operation fails.
$files[]=$targetpath;
# save image details... or try to
$stmt->execute();
}
}
#commit to database or erase files if there is a problem
if( !$db->commit() ) {
$errors[]='Failed to commit transaction';
foreach( $files as $file ){
unlink( $file );
$errors[]=sprintf('File deleted: "%s"',$file);
}
$uploads=[];
}
}
}
}catch( Exception $e ){
$errors[]=$e->getMessage();
}
}
?>
<!DOCTYPE html>
<html lang='en'>
<head>
<title>PHP: Multiple file uploads - different inputs</title>
<meta charset='utf-8' />
<style>
form{width:60%;float:none;margin:1rem auto;padding:0.5rem 1rem;font-family:monospace;border:1px dashed gray;border-radius:0.5rem;background:whitesmoke;}
label{width:80%;margin:0.75rem auto;display:block;float:none;padding:0.25rem;}
label > input{float:right;width:75%;}
fieldset{margin:1rem auto;padding:1rem;border:1px solid rgba(100,100,100,0.5);background:white;border-radius:0.5rem;}
form > div{margin:1rem auto}
[type='submit']{padding:1rem;}
[type='file']{border:1px solid rgba(100,100,100,0.5); padding:0.25rem;border-radius:0.25rem;color:rgba(100,100,100,0.5);background:rgba(200,200,200,0.5);}
legend{background:rgba(100,100,100,0.5);color:white;padding:0.5rem;border-radius:0.5rem;min-width:20%;}
.error{color:red;}
.success{color:green;}
</style>
</head>
<body>
<form name=uploads' method='post' enctype='multipart/form-data'>
<fieldset>
<legend>Product</legend>
<label>Name:<input type='text' name='productname' /></label>
<label>Brand:<input type='text' name='productbrand' /></label>
</fieldset>
<fieldset>
<legend>Product images</legend>
<label>Image-Face:<input type='file' name='productimage[FaceProduct]' /></label>
<label>Image-Nutrition:<input type='file' name='productimage[NutritionValue]' /></label>
<!-- other images could be added using same method but different index values ~ EG: -->
<label>Image-Ingredients:<input type='file' name='productimage[Ingredients]' /></label>
<label>Image-Labels:<input type='file' name='productimage[Labels]' /></label>
</fieldset>
<fieldset>
<legend>User details</legend>
<label>Added by:<input type='text' name='addername' /></label>
<label>Email:<input type='text' name='adder_email' /></label>
</fieldset>
<fieldset>
<input type='submit' />
</fieldset>
<div>
<?php
if( $_SERVER['REQUEST_METHOD']=='POST' ){
if( !empty( $uploads ) ){
foreach( $uploads as $message )printf('<div class="success">%s</div>',$message);
}
if( !empty( $errors ) ){
foreach( $errors as $message )printf('<div class="error">%s</div>',$message);
}
$errors=$uploads=array();
}
?>
</div>
</form>
</body>
</html>
Upvotes: 0
Reputation: 23
Thank you @Professor I create the table, tested the page but two things are strange :
Here the messages I got:
The file "130_Candy_Produit_FaceProduct_pic01.jpg" has been uploaded OK. Information has been added to the directory: True There was a problem saving "130_Candy_Produit_NutritionValue_". Information logged to db: True There was a problem saving "130_Candy_Produit_Ingredients_". Information logged to db: True There was a problem saving "130_Candy_Produit_Labels_". Information logged to db: True
And here the code:
error_reporting( E_ALL );
class PostException extends Exception {
public function __construct( $msg=null, $code=null ){
parent::__construct( $msg, $code );
}
public function geterror(){
return $this->getMessage();
}
}
if( $_SERVER['REQUEST_METHOD']=='POST' ){
try{
#look at the form - see how it is using this for image name
$field='productimage';
if( isset(
$_FILES[ $field ],
$_POST['productname'],
$_POST['productbrand'],
$_POST['addername'],
$_POST['adder_email']
) ){
$errors=array();
$uploads=array();
$files=array();
$lineid=false;
$dbstatus=false;
#################################
# edit this as appropriate...
$dir=__DIR__ . '/imagesStack';
# the names of the various fields in the form - not images
$args=array(
'productname',
'productbrand',
'addername',
'adder_email'
);
/*
loop through the `$args` array - if a field in the FORM
is not set or empty throw & catch a custom exception -
the errors will be displayed later.
If no errors, generate the variables based upon the name of
the field using variable variables.
*/
foreach( $args as $fieldname ){
try{
if( !isset( $_POST[ $fieldname ] ) or empty( $_POST[ $fieldname ] ) )throw new PostException( sprintf( 'Missing data: The field "%s" is required.', $fieldname ) );
else{
${$fieldname}=$_POST[ $fieldname ];
}
}catch( PostException $e ){
$errors[]=$e->geterror();
continue;
}
}
if( empty( $errors ) ){
$args=array(
'host' => 'localhost',
'user' => 'FFFFF',
'pwd' => 'EEEEEEEE',
'db' => 'GGGGGGGGGG'
);
mysqli_report( MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT );
$db=new mysqli( ...array_values( $args ) );
$db->set_charset('utf8');
$db->begin_transaction();
#create the basic sql and prepared statement
$sql='insert into `cbnadd_newproduct`
( `productname`, `productbrand`, `addername`, `adder_email` )
values
( ?,?,?,? )';
$stmt=$db->prepare( $sql );
/* bind params and execute */
$stmt->bind_param('ssss', $productname, $productbrand, $addername, $adder_email );
$dbstatus=$stmt->execute();
/* get the ID of the last inserted record */
$lineid=$db->insert_id;
$stmt->close();
/*
It would be usual to record the names / paths of images
that you upload so I created a new table for that purpose
*/
# insert records for new images to other table.
$sql='insert into `cbnadd_productimages` (`lineid`,`image`) values (?,?)';
$stmt=$db->prepare( $sql );
$stmt->bind_param('is', $lineid, $targetname );
/*
Process the file uploads - using the Array syntax
means you can easily loop through all the files &
rename and log to db.
*/
$obj=$_FILES[ $field ];
foreach( $obj['name'] as $index => $void ){
$name=$obj['name'][ $index ];
$tmp=$obj['tmp_name'][ $index ];
# new image name format "id_brand_product_category_filename.ext"
$targetname=sprintf('%d_%s_%s_%s_%s', $lineid, $productbrand, $productname, $index, $name );
# full path for the image to be saved to
$targetpath=sprintf('%s/%s', $dir, $targetname );
# move the file
$status=move_uploaded_file( $tmp, $targetpath );
# upload the output variable
$uploads[]=$status ? sprintf('The file "%s" has been uploaded OK. Information has been added to the directory: %s', $targetname, ( $dbstatus ? 'True' : 'False' ) ) : sprintf('There was a problem saving "%s". Information logged to db: %s ',$targetname, ( $dbstatus ? 'True' : 'False' ) );
# maintain a list of files to be used if db operation fails.
$files[]=$targetpath;
# save image details... or try to
$stmt->execute();
}
#commit to database or erase files if there is a problem
if( !$db->commit() ) {
$errors[]='Failed to commit transaction';
foreach( $files as $file ){
unlink( $file );
$errors[]=sprintf('File deleted: "%s"',$file);
}
$uploads=[];
}
}
}
}catch( Exception $e ){
$errors[]=$e->getMessage();
}
}
?>
<!DOCTYPE html>
<html lang='en'>
<head>
<title>PHP: Multiple file uploads - different inputs</title>
<meta charset='utf-8' />
<style>
form{width:60%;float:none;margin:1rem auto;padding:0.5rem 1rem;font-family:monospace;border:1px dashed gray;border-radius:0.5rem;background:whitesmoke;}
label{width:80%;margin:0.5rem auto;display:block;float:none;padding:0.25rem;}
label > input{float:right;width:75%;}
fieldset{margin:1rem auto;padding:1rem;border:1px solid rgba(100,100,100,0.5);background:white;border-radius:0.5rem;}
form > div{margin:1rem auto}
[type='submit']{padding:1rem;}
legend{background:rgba(100,100,100,0.5);color:white;padding:0.5rem;border-radius:0.5rem;min-width:20%;}
.error{color:red;}
.success{color:green;}
</style>
</head>
<body>
<form name='uploads' method='post' enctype='multipart/form-data'>
<fieldset>
<legend>Product</legend>
<label>Name:<input type='text' name='productname' /></label>
<label>Brand:<input type='text' name='productbrand' /></label>
</fieldset>
<fieldset>
<legend>Product images</legend>
<label>Image-Face:<input type='file' name='productimage[FaceProduct]' /></label>
<label>Image-Nutrition:<input type='file' name='productimage[NutritionValue]' /></label>
<!-- other images could be added using same method but different index values ~ EG: -->
<label>Image-Ingredients:<input type='file' name='productimage[Ingredients]' /></label>
<label>Image-Labels:<input type='file' name='productimage[Labels]' /></label>
</fieldset>
<fieldset>
<legend>User details</legend>
<label>Added by:<input type='text' name='addername' /></label>
<label>Email:<input type='text' name='adder_email' /></label>
</fieldset>
<fieldset>
<input type='submit' />
</fieldset>
<div>
<?php
if( $_SERVER['REQUEST_METHOD']=='POST' ){
if( !empty( $uploads ) ){
foreach( $uploads as $message )printf('<div class="success">%s</div>',$message);
}
if( !empty( $errors ) ){
foreach( $errors as $message )printf('<div class="error">%s</div>',$message);
}
}
?>
</div>
</form>
</body>
</html>
Upvotes: 1