I am trying to upload multiple images for a product for an eCommerce website. The idea is to save the service name in the services table while the images are saved in the service_images table, but whenever I run the php file, it uploads the service to the services table but only uploads one image to the service_images table instead of all the images. How can I get it to upload one service in the services table and also multiple images of that one service in the service_images table?
Below is my code:
add-service.inc.php
<?php
if (isset($_POST['add-service'])) {
require 'config.php';
$shop_name = mysqli_real_escape_string($conn, $_POST['shop_name']);
$service_cat = mysqli_real_escape_string($conn, $_POST['service_cat']);
$service_name = mysqli_real_escape_string($conn, $_POST['service_name']);
$service_desc = mysqli_real_escape_string($conn, $_POST['service_desc']);
$service_price = mysqli_real_escape_string($conn, $_POST['service_price']);
$service_type = mysqli_real_escape_string($conn, $_POST['service_type']);
$service_images = $_FILES['service_images'];
if (empty($shop_name) || empty($service_cat) || empty($service_name) || empty($service_desc) || empty($service_price) || empty($service_type)) {
header('Location: ../services.php?error=emptyFields');
exit();
} elseif (!preg_match('/^[a-zA-Z0-9]*$/', $shop_name) && !preg_match('/^[a-zA-Z0-9\s]*$/', $service_name) && !preg_match('/^[a-zA-Z0-9\s \. \-]*$/', $service_desc) && !preg_match('/^[0-9\.]*$/', $service_price) && !preg_match('/^[a-zA-Z0-9\s \.]*$/', $service_type)) {
header('Location: ../services.php?error=invalidInputs');
exit();
} elseif (!preg_match('/^[a-zA-Z0-9]*$/', $shop_name)) {
header('Location: ../services.php?error=invalidShopName');
exit();
} elseif (!preg_match('/^[a-zA-Z0-9\s]*$/', $service_name)) {
header('Location: ../services.php?error=invalidserviceName');
exit();
} elseif (!preg_match('/^[a-zA-Z0-9\s \. \-]*$/', $service_desc)) {
header('Location: ../services.php?error=invalidDescription');
exit();
} elseif (!preg_match('/^[0-9\.]*$/', $service_price)) {
header('Location: ../services.php?error=invalidPrice');
exit();
} elseif (!preg_match('/^[a-zA-Z0-9\s \.]*$/', $service_type)) {
header('Location: ../services.php?error=invalidStyle');
exit();
} else {
foreach ($_FILES["service_images"]["tmp_name"] as $key => $tmp_name) {
$file_name = $_FILES["service_images"]["name"][$key];
$file_type = $_FILES["service_images"]["type"][$key];
$file_tempName = $_FILES["service_images"]["tmp_name"][$key];
$file_error = $_FILES["service_images"]["error"][$key];
$file_size = $_FILES["service_images"]["size"][$key];
$a = count($_FILES['service_images']['name']);
for ($i = 0; $i < $a; $i++) {
$fileExt = explode('.', $file_name);
$fileActualExt = strtolower(end($fileExt));
$allowed = array('jpg', 'png', 'jpeg');
if (in_array($fileActualExt, $allowed)) {
if ($file_error === 0) {
if ($file_size <= 15000000) {
$newFileName = preg_replace('/\s+/', '', $service_name) . $i . '.' . $fileActualExt;
echo $newFileName . "<br>";
$fileDestination = '../../services/' . $newFileName;
$sql_images = "INSERT INTO service_images (shop_name, service_name) VALUES ('$shop_name', '$service_name')";
$result = mysqli_query($conn, $sql_images);
$sql = "INSERT INTO services (shop_name, service_cat, service_name, service_desc, service_price, service_type) VALUES (?,?,?,?,?,?)";
$stmt = mysqli_stmt_init($conn);
if (!mysqli_stmt_prepare($stmt, $sql)) {
header("Location: ../services.php?error=SaveError");
exit();
} else {
mysqli_stmt_bind_param($stmt, 'ssssss', $shop_name, $service_cat, $service_name, $service_desc, $service_price, $service_type);
mysqli_stmt_execute($stmt);
// move_uploaded_file($file_tempName = $_FILES["service_images"]["tmp_name"][$i], $fileDestination);
header("Location: ../services.php?success");
exit();
}
} else {
header('Location: ../services.php?error=invalidSize');
exit();
}
} else {
header('Location: ../services.php?error=invalidImage');
exit();
}
} else {
header('Location: ../services.php?error=invalidImageType');
exit();
}
}
}
}
}
form
<form action="../admin/includes/add-service.inc.php" method="post" enctype="multipart/form-data">
<input type="text" name="shop_name" id="shopName" class="form-input" placeholder="Shop Name">
<select name="service_cat" id="serviceCat" class="form-input">
<option> -- select category -- </option>
<?php
$sql = "SELECT * FROM service_category";
$result = mysqli_query($conn, $sql);
if (mysqli_num_rows($result) > 0) {
while ($row = mysqli_fetch_assoc($result)) {
?>
<option value="<?php echo $row['service_cat'] ?>"><?php echo $row['service_cat'] ?></option>
<?php
}
}
?>
</select>
<input type="text" name="service_name" id="serviceName" class="form-input" placeholder="Service Name">
<textarea name="service_desc" id="service_desc" cols="1" rows="5" placeholder="Description" class="form-input"></textarea>
<input type="text" name="service_price" id="servicePrice" class="form-input" placeholder="Service Price">
<input type="text" name="service_type" id="serviceType" class="form-input" placeholder="Service Type">
<hr>
<label for="serviceImages">*Select all pictures for your service</label>
<input type="file" name="service_images[]" id="serviceImages" class="form-input" multiple>
<button type="submit" class="btn-add" name="add-service">Add Service</button>
</form>
First of all, you have the same loop twice. First as foreach and then as for. Since you need numeric keys from this weird array type of $_FILES, then your best approach is to use for loop only.
These double loops are already so messy, that could cause unexpected issues, if one of the files has a problem for example.
But, your main issue is, that you are basically checking only one image and then uploading it. If the validation process or success goes trough, it has exit(); at the end. It kills not only the loop, but the entire script. You are not allowing the second image loop to continue, as first one kills it.. either on success or error.
Solution would be to wait for the loops to finish (adding code after the loops brackets) and putting the success related code there. If an error is detected inside the loops, then the script never gets that far.
I have no idea, how you are actually linking the images to service, but I tried to clean up your code and make the order correct. I also did my best at explaining why and where. Hopefully, you understand the problem better from this or even better, find better options to optimise your code:
// TESTING: Lets see what is inside post values:
echo '<b>$_POST values</b><pre>'; print_r($_POST); echo '</pre>';
// TESTING: Lets see what is inside the files values:
echo '<b>$_FILES values</b><pre>'; print_r($_FILES); echo '</pre>';
// Above is for testing only..
// Probably better place to load important configs:
require 'config.php';
// Since these are the conditions for uploads, then they are global:
// no need for them to be inside the loop:
$allowed = array('jpg', 'png', 'jpeg');
// Maximum allowed filesize:
$max_allowed_file_size = 15000000; // which is 15mb
// We detect the submit buttons trigger name:
if (isset($_POST['add-service'])) {
// Do the escape thingy:
// NOTE: You should be using some mysqli class for database handling:
$shop_name = mysqli_real_escape_string($conn, $_POST['shop_name']);
$service_cat = mysqli_real_escape_string($conn, $_POST['service_cat']);
$service_name = mysqli_real_escape_string($conn, $_POST['service_name']);
$service_desc = mysqli_real_escape_string($conn, $_POST['service_desc']);
$service_price = mysqli_real_escape_string($conn, $_POST['service_price']);
$service_type = mysqli_real_escape_string($conn, $_POST['service_type']);
$service_images = $_FILES['service_images'];
// Lets deal with the errors before going forward with the rest of the script:
// You don't need elseif here, because your callback is to redirect and exit anyways..
if (empty($shop_name) || empty($service_cat) || empty($service_name) || empty($service_desc) || empty($service_price) || empty($service_type)) {
header('Location: ../services.php?error=emptyFields');
exit();
}
if (!preg_match('/^[a-zA-Z0-9]*$/', $shop_name) && !preg_match('/^[a-zA-Z0-9\s]*$/', $service_name) && !preg_match('/^[a-zA-Z0-9\s \. \-]*$/', $service_desc) && !preg_match('/^[0-9\.]*$/', $service_price) && !preg_match('/^[a-zA-Z0-9\s \.]*$/', $service_type)) {
header('Location: ../services.php?error=invalidInputs');
exit();
}
if (!preg_match('/^[a-zA-Z0-9]*$/', $shop_name)) {
header('Location: ../services.php?error=invalidShopName');
exit();
}
if (!preg_match('/^[a-zA-Z0-9\s]*$/', $service_name)) {
header('Location: ../services.php?error=invalidserviceName');
exit();
}
if (!preg_match('/^[a-zA-Z0-9\s \. \-]*$/', $service_desc)) {
header('Location: ../services.php?error=invalidDescription');
exit();
}
if (!preg_match('/^[0-9\.]*$/', $service_price)) {
header('Location: ../services.php?error=invalidPrice');
exit();
}
if (!preg_match('/^[a-zA-Z0-9\s \.]*$/', $service_type)) {
header('Location: ../services.php?error=invalidStyle');
exit();
}
// Nothing happened above, so that means the form validation should be fine and we can go forward with the images:
// So as in your script, we count the images:
$a = count($_FILES['service_images']['name']);
// Now we do a "numeric loop", not an array loop, which is foreach:
for ($i = 0; $i < $a; $i++) {
// Since we have the key as numeric now, we can do what you did before, but without the foreach loop:
$file_name = $_FILES['service_images']['name'][$i];
$file_type = $_FILES['service_images']['type'][$i];
$file_tempName = $_FILES['service_images']['tmp_name'][$i];
$file_error = $_FILES['service_images']['error'][$i];
$file_size = $_FILES['service_images']['size'][$i];
// Get the file extension:
// NOTE: This is not good, as you should really check the mime type of the file, not the extension.
$fileActualExt = strtolower(end(explode('.', $file_name)));
// TESTING: We check print out the data to make sure, that all looks fine:
echo 'File with the key: ' . $i .' -- $file_name: ' . $file_name . '; $file_type: ' . $file_type . '; $file_tempName: ' . $file_tempName . '; $file_error: ' . $file_error . '; $file_size: ' . $file_size . '<br>';
// Instead of making the code ugly, lets deal with errors, by killing the script before
// NOTE: This is not good approach, you should be using Exceptions:
// https://www.php.net/manual/en/language.exceptions.php
// Check if the file extension is NOT in the allowed array
if (!in_array($fileActualExt, $allowed)) {
// Redirect:
header('Location: ../services.php?error=invalidImageType');
// Kill the script:
exit('invalidImageType');
}
// Check if the file had an error:
if ($file_error) {
// Redirect:
header('Location: ../services.php?error=invalidImage');
// Kill the script:
exit('invalidImage');
}
// Check if the image bytes are BIGGER > then max allowed file size variable:
if ($file_size > $max_allowed_file_size) {
// Redirect:
header('Location: ../services.php?error=invalidSize');
// Kill the script:
exit();
}
// At this stage, hopefully, there has not been any errors above and we can deal with file freely:
// Make new file name:
$newFileName = preg_replace('/\s+/', '', $service_name) . $i . '.' . $fileActualExt;
// echo $newFileName . "<br>";
// Set the new destination:
$fileDestination = '../../services/' . $newFileName;
// Lets move the file already.
// NOTE: Make sure that you have some bash code from server side, that deletes outdated / old temp files, so they dont take space:
move_uploaded_file($file_tempName = $_FILES["service_images"]["tmp_name"][$i], $fileDestination);
// Insert the image to database:
// NOTE: Im not sure about your specific code, but just this is there location for that:
$sql_images = "INSERT INTO service_images (shop_name, service_name) VALUES ('$shop_name', '$service_name')";
$result = mysqli_query($conn, $sql_images);
// PROBLEM: This is where you originally had the success message redirect and exit.
// This means, you KILL the script and there for the loop.
// But you have to understand, that you have two images or more, so the loop has to continue freely,
// and you can do this sort of stuff at after the loop!
//
// header("Location: ../services.php?success");
// exit();
}
// If nothing happened above, then the image uploads went trough nicely and we can deal with success messages or adding the service itself:
// I have not used mysqli stmpt before, so I have no idea what is going on in this area..:
// .. but this the locatin to deal with the services as this is the parent and the children are above.
$sql = "INSERT INTO services (shop_name, service_cat, service_name, service_desc, service_price, service_type) VALUES (?,?,?,?,?,?)";
$stmt = mysqli_stmt_init($conn);
// I don't think you need this at all, but whatever:
// Shouldnt this be above
if (!mysqli_stmt_prepare($stmt, $sql)) {
// Redirect:
header("Location: ../services.php?error=SaveError");
// Kill the script:
exit();
}
// This is adding the service I assume, it has to be outside the loop, as single submit = single service. But images are multiple.
mysqli_stmt_bind_param($stmt, 'ssssss', $shop_name, $service_cat, $service_name, $service_desc, $service_price, $service_type);
mysqli_stmt_execute($stmt);
// This is where you can have the success redirect and exit, as this is after the loop:
header("Location: ../services.php?success");
exit();
}
NOTES:
You should be using Exceptions for your error handling.
Learn the difference between foreach and for loops.
File extensions can be tricked, check out the file mime type instead
Allowed file types array inside the loop is not very smart, as you will use it it more than once in all the loop cycles. Best to keep it at the top of the script, so its easier to setup in the future. Same goes for the filesize variable.
It would make alot more sense to detect the file types, sizes via javascript before they even get to your server. This way you save temp file folder space issues and bandwidth basically.
I don't understand where you actually use $result from the mysql. Or where do you link the images from service_images table to the actual service.
Use <input type="file" name="service_images[]" multiple accept=".jpg, .png, .jpeg"> (the multiple accept=".jpg, .png, .jpeg") in the form to not allow the user to pick any other extensions. You can also use "images" value for all images.
What's wrong with this preg_match() usage? I want to check steam lobby link and if it's matching then write to database. If not, just echo the error. I am doing this through ajax. Is it better to do this with ajax or $_SERVER["REQUEST_METHOD"] == "POST"?
<?php
require("../includes/config.php");
$lobby = "steam://joinlobby/730/109775243427128868/76561198254260308";
if (!preg_match("%^((steam?:)+(/joinlobby\/730\/)+([0-9]{17,25}\/.?)+([0-9]{17,25})/$)%i", $lobby)) {
echo "Lobby link isn't formatted correctly.";
}
else {
$rank = "Golden";
$mic = "No";
try {
$stmt=$db->prepare("INSERT INTO created_lobby (lobby_link, current_rank, have_mic) VALUES (:lobby_link, '$rank', '$mic')");
$stmt->execute(array(
':input_link' => $_POST['lobbyLink']
));
}
catch(PDOException $e) {
echo "Error: " . $e->getMessage();
}
}
?>
My Problem:
When I execute this code, it will give me false.
Thank you for help.
This works:
$lobby = "steam://joinlobby/730/109775243427128868/76561198254260308";
if (!preg_match("%^(steam?:)+(//joinlobby/730/)+([0-9]{17,25}/.?)+([0-9]{17,25}$)%i", $lobby)) {
echo "Lobby link isn't formatted correctly.";
}
I changed /joinlobby to //joinlobby, and remove the / at the end. I also removed the unnecessary () around everything.
I suspect you also shouldn't have (...)+ around steam?: and //joinlobby/730/. They'll cause repeated uses of those prefixes to be accepted as correct, e.g. steam:steam:...
I'm having trouble creating a form that exports to a .CSV file in PHP. I created a fiddle for the HTML which is here:
http://jsfiddle.net/tqs6g/
I'm coding in PHP so I can't really show the full code on JSFiddle since it can't support the PHP but here's my PHP code:
<?php
if($_POST['formSubmit'] == "Submit")
{
$errorMessage = "";
if(empty($_POST['brandname']))
{
$errorMessage .= "<li>Please enter a business/brand name.</li>";
}
if(empty($_POST['firstname']))
{
$errorMessage .= "<li>Please enter your first name.</li>";
}
$varBrand = $_POST['brandname'];
$varFName = $_POST['firstname'];
$varLName = $_POST['lastname'];
$varEmail = $_POST['email'];
$varSite = $_POST['website'];
if(empty($errorMessage))
{
$fs = fopen("mydata.csv","a");
fwrite($fs,$varBrand . ", " . $varFName . ", " . $varLName . ", " . $varEmail . ", " . $varSite . "\n");
fclose($fs);
exit;
}
}
?>
When I click Submit it successfully goes to 'thankyou.php' (which is set in the form action) but I can't figure out why it's not posting the correct error messages or filling in my 'mydata.csv' file upon click. Possibly it's a sight syntax error? Let me know if you need any more info, I know this is kind of confusing seeing as the PHP is separated from the Fiddle.
<?php
if ($_SERVER['REQUEST_METHOD'] == 'POST') { // better method to check for a POSt
... validation stuff ...
$data = array();
$data[] = $_POST['brandname'];
$data[] = $_POST['firstname'];
etc...
if (empty($errrorMessage)) {
$fs = fopen('mydata.csv', 'a') or die("Unable to open file for output");
fputcsv($fs, $data) or die("Unable to write to file");
fclose($fs);
exit();
} else {
echo $errormessage;
}
}
A few things of note:
1) using $_SERVER['REQUEST_METHOD'] to check for submit type is absolutely reliable - that value is always set, and will always be POST if a post is being performed. Checking for a particular form field (e.g. the submit button) is hacky and unreliable.
2) Using fputcsv() to write out to a csv file. PHP will do all the heavy work for you and you jus tprovide the function an array of data to write
3) Note the or die(...) constructs, which check for failures to open/write to the file. Assuming that a file is available/writeable is unreliable and will bite you at some point in the future. When dealing with "external" resources, always have error handling.
look at this code
<?
require_once("conn.php");
require_once("includes.php");
require_once("access.php");
if(isset($_POST[s1]))
{
//manage files
if(!empty($_FILES[images]))
{
while(list($key,$value) = each($_FILES[images][name]))
{
if(!empty($value))
{
$NewImageName = $t."_".$value;
copy($_FILES[images][tmp_name][$key], "images/".$NewImageName);
$MyImages[] = $NewImageName;
}
}
if(!empty($MyImages))
{
$ImageStr = implode("|", $MyImages);
}
}
$q1 = "insert into class_catalog set
MemberID = '$_SESSION[MemberID]',
CategoryID = '$_POST[CategoryID]',
Description = '$_POST[Description]',
images = '$ImageStr',
DatePosted = '$t',
DateExp = '$_SESSION[AccountExpDate]',
FeaturedStatus = '$_POST[sp]' ";
//echo $q1;
mysql_query($q1) or die(mysql_error());
}
//get the posted offers
$q1 = "select count(*) from class_catalog where MemberID = '$_SESSION[MemberID]' ";
$r1 = mysql_query($q1) or die(mysql_error());
$a1 = mysql_fetch_array($r1);
header("location:AddAsset.php");
exit();
?>
The mySql insert function isn't adding anything also it return success to me , I've tried using INSERT ... Values but what it done was overwtiting existing value ( i.e make 1 entry and overwties it everytime).
I am using PHP 4.4.9 and MySql 4
I tried to add from Phpmyadmin and it is working also it was working after installation but after i quit the browser and made a new account to test it it is not working but the old ones is working ! you can see it here http://bemidjiclassifieds.com/
try to login with usr:openbook pass:mohamed24 and you can see it will be working but any new account won't work!
Maybe $_POST[s1] is not set or you are inserting into a different database than you are watching.
if(isset($_POST[s1]))
should probably be
if(isset($_POST['s1']))
(note the quotes). Also, it's best to NOT depend on a field being present in the submitted data to check if you're doing a POSt. the 100% reliable method is
if ($_SERVER['REQUEST_METHOD'] == 'POST') { ... }
As well, you're not checking if the file uploads succeeded. Each file should be checked like this:
foreach($_FILES['images']['name'] as $key => $name) {
if ($_FILES['images']['error'][$key] !== UPLOAD_ERR_OK) {
echo "File #$key failed to upload, error code {$_FILES['images']['error'][$key]}";
}
...
}
Don't use copy() to move uploaded files. There's a move_uploaded_files() function for that, which does some extra sanity checking to make sure nothing's tampered with the file between the time the upload finished and your script tries to move it.
i am trying to use the !isset on the '$class' variable to see if it has a value or not, and then base the mysql_query function on that. but it's a no go. see anything wrong?
<?php session_start();
$heyyou = $_SESSION['usern'];
$points = $_SESSION['points'];
$school = $_SESSION['school'];
$class = $_POST['class'];
$prof = $_POST['prof'];
$date = $_POST['dater'];
$fname = $_FILES['fileToUpload']["name"];
?>
<div id='contenttext' class='contenttext'>
<?php
#mysql_select_db($database) or die( "Unable to select database");
$query = "INSERT INTO uploadedfiles (usename, filename, date, teacher, class) VALUES ('$heyyou', '$fname', '$date', '$prof', '$class')";
if (!isset($class)){
echo 'You need to pick a class for the content'; }
else{
mysql_query($query); }
mysql_close();
?>
<?php
if (($_FILES["fileToUpload"]["type"] == "image/gif" || $_FILES["fileToUpload"]["type"] == "image/jpeg" || $_FILES["fileToUpload"]["type"] == "image/png") && $_FILES["fileToUpload"]["size"] < 10000000)
{
move_uploaded_file($_FILES["fileToUpload"]["tmp_name"],
"upload/" . $_FILES["fileToUpload"]["name"]);
echo "Your file has successfully been uploaded, and is awaiting moderator approval for points." . "<html><br><a href='uploadfile.php'>Upload more.</a>";
}
else
{
echo "Files must be either JPEG, GIF, or PNG and less than 10,000 kb";
}
?>
</div>
</body>
</html>
Two major security problems with your code:
You're wide open to SQL injection attacks (see: http://bobby-tables.com/)
You're blindly trusting the user is not malicious for the file upload. The ['type'] and ['name'] fields are completely under user control, and it's trivial to hack the upload to say it's a gif while still uploading a PHP script. You then use the user-supplied filename, WHICH CAN CONTAIN PATH INFORMATION, and dump it directly to your server. This leaves the door wide open to a malicious user uploading any file they want, anywhere on the server.
Minor point #3:
You don't check if the database query succeeds. Never assume a query succeeds. Even if the SQL statement is perfectly valid, there's far too many other reasons that could make it fail anyways. Always check the query call with ... = mysql_query(...) or die(mysql_error()) as a bare minimum error handler.
Probably because $class is being set, by you. Try if (empty($class)){
I maybe wrong but class is a reserved word try another name and $class != ""
http://www.php.net/manual/en/reserved.keywords.php
BTW remove you DB Conect info please we me be nice but some of the people reading this may not be. ;-)
Try this, first initialize all your variables and then assign the POST values.
Eg:
$class='';
$class = $_POST['class'];
if (!isset($class)){
echo 'You need to pick a class for the content';
}
You can not use $class since class is a keyword reserved.
This may work too:
$query = "INSERT INTO uploadedfiles (usename, filename, date, teacher, class) VALUES ($heyyou, $fname, $date, $prof, $class)";
Since double quote can understand variables when they inside it.
Another think is date is a keyword too reserved by MySQL.
Finlly try to see what $_POST['class']; content like this:
echo $_POST['class'];
Because perhaps you forget to give a name to your html element.
The variable $class is always set because of $class = $_POST['class']. so isset($class) will always be true regardless of class posted value. notice the difference in below statements:
$class = '';
if (isset($class)) {
echo 'a';
}
if($class) {
echo 'b';
}
the output is: a
//replace this:
if (!isset($class)){
echo 'You need to pick a class for the content'; }
else{
mysql_query($query);
}
//with this:
if (isset($class) && $class){
mysql_query($query);
else{
echo 'You need to pick a class for the content'; }
}