I've made a html form using Bootstrap. I've used "required" to ensure data is populated in certain fields for the form to be submitted. This form goes to a php script that opens a database connection, inputs the values as per form submitted, directs to a thank you page and closes the connection.
Its my first hand coded form and my concern is security. How do I keep hackers/spammers at bay?
Can you point out, please, issues with my code so I can address them before I put this live. Please be gentle, Im a newbie with about 3 months of coding experience.
Please note the original form actually has 9 fields but I've omitted it presuming those details wont be necessary for this discussion.
HTML Code
<form class="form-horizontal" method="post" action="vacancy.php">
<div class="form-group">
<label for="company" class="col-sm-3 control-label">Company Name *</label>
<div class="col-sm-6">
<input type="text" name="company" class="form-control" placeholder="Enter Company Name" required />
</div>
</div>
<div class="form-group">
<label for="contactperson" class="col-sm-3 control-label">Contact Person *</label>
<div class="col-sm-6">
<input type="text" name="contactperson" class="form-control" placeholder="Enter Full Name" required />
</div>
</div>
<div class="form-group">
<label for="designation" class="col-sm-3 control-label">Designation *</label>
<div class="col-sm-6">
<input type="text" name="designation" class="form-control" placeholder="Enter Designation" required />
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-6">
<button type="submit" class="btn btn-primary">Submit</button>
<button type="reset" class="btn btn-default">Clear</button>
</div>
</div>
</form>
PHP Code
<?php
$con=mysqli_connect("localhost","db2u","password","db2");
if (mysqli_connect_errno())
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
$sql="INSERT INTO vacancy (Company, ContactPerson, Designation)
VALUES
('$_POST[company]','$_POST[contactperson]','$_POST[designation]')";
if (!mysqli_query($con,$sql))
{
die('Error: ' . mysqli_error($con));
}
header("Location: thankyou.html");
mysqli_close($con);
?>
EDIT : So it seems I need validation. Im looking at jqBootstrapValidation. Even considering htmlspecialchars (which ever is easier). I believe both would do an equally good job right? PDO is a bit too much for me at the moment.
Your code could be compromised by SQL injection http://en.wikipedia.org/wiki/SQL_injection.
Try use htmlspecialchars or better use PDO instead of OLD and DANGEROUS mysql_* functions.
You have not validated any field in your php code,
you should put validation in php file too, any user can remove "required" from input and can post the data.
Never trust the user input. You should escape the strings with mysqli_real_escape_string() function.
http://www.php.net/manual/en/mysqli.real-escape-string.php
$company = mysqli_real_escape_string($_POST[company]);
$contactperson = mysqli_real_escape_string($_POST[contactperson]);
$designation = mysqli_real_escape_string($_POST[designation]);
$sql="INSERT INTO vacancy (Company, ContactPerson, Designation) VALUES ('$company','$contactperson','$designation')";
Related
New to php, would appreciate your help with this:
I made a signup form script to validate the user's input via multiple error handlers. (check valid email, pwd and pwd re-entry match etc).
In case the user filled all fields but one had an error (failed to pass the error handler), i wanted to send back the other fields to the same form so the user doesn't have to refill'm all over again. So if the passwords dint match, i wanted to reload the same page but with the other filed filled.
i can see the information in the url of the page but not in the form fields.
below my form HTML
<div class="register-content">
<form action="includes/signup.inc.php" method="POST" class="margin-bottom-0">
<label class="control-label">Name <span class="text-danger">*</span></label>
<div class="row row-space-10">
<div class="col-md-6 m-b-15">
<input type="text" name="uFirst" class="form-control" placeholder="First name" required />
</div>
<div class="col-md-6 m-b-15">
<input type="text" name="uLast" class="form-control" placeholder="Last name" required />
</div>
</div>
<label class="control-label">Username <span class="text-danger">*</span></label>
<div class="row m-b-15">
<div class="col-md-12">
<input type="text" name="uName" class="form-control" placeholder="Username" required />
</div>
</div>
<label class="control-label">Email <span class="text-danger">*</span></label>
<div class="row m-b-15">
<div class="col-md-12">
<input type="text" name="mail" class="form-control" placeholder="Email address" required />
</div>
</div>
<label class="control-label">Password <span class="text-danger">*</span></label>
<div class="row m-b-15">
<div class="col-md-12">
<input type="password" name="pwd" class="form-control" placeholder="Password" required />
</div>
</div>
<label class="control-label">Re-enter Password <span class="text-danger">*</span></label>
<div class="row m-b-15">
<div class="col-md-12">
<input type="password" name="pwd-repeat" class="form-control" placeholder="Re-enter Password" required />
</div>
</div>
Below my php code
<?php if(isset($_POST['signup-submit'])) {
require 'dbh.inc.php';
$firstName=$_POST['uFirst'];
$lastName=$_POST['uLast'];
$userName=$_POST['uName'];
$email=$_POST['mail'];
$password=$_POST['pwd'];
$passwordRepeat=$_POST['pwd-repeat'];
if (!filter_var($email, FILTER_VALIDATE_EMAIL) && !preg_match("/^[a-zA-Z0-9]*$/", $username)) {
header("location: ../signup.php?error=invalidemail&uid&uFirst=".$firstName."&uLast=".$lastName);
exit();
} else if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
header("location: ../signup.php?error=invalidemail&uFirst=".$firstName."&uLast=".$lastName."&uName=".$userName);
exit();
} else if (!preg_match("/^[a-zA-Z0-9]*$/", $username)) {
header("location: ../signup.php?error=invaliduid&uFirst=".$firstName."&uLast=".$lastName."&mail=".$email);
exit();
} else if ($password !== $passwordRepeat) {
header("location: ../signup.php?error=passwordnotmatching&uFirst=".$firstName."&uLast=".$lastName."&uName=".$userName."&mail=".$email);
exit();
?>
There are several ways to address this. Ultimately, there are two high-level options:
Pass the valid values back into the new form
Never remove the valid values(i.e. JavaScript + AJAX)
With your current setup, (1) would be simpler. To work with your current design, you would need to store the values somewhere to pass back to the form to render. The simplest would be to add them to the URL parameters(query string), but other options include cookies or session storage.
The simplest option would be to combine your form and validation into a single endpoint rather than separating them. That way, you already have the post data when rendering the form with the error messages.
Once you have the values, you can simply insert them into the form HTML with the value attribute(be sure to HTML encode(htmlentities) any user input values to avoid XSS vulnerabilities).
For example:
<input type="text" name="uFirst" class="form-control" placeholder="First name" value="<?= htmlentities($firstName) ?>" required />
I just noticed(from one of the comments) that you are already passing your valid values in the query string with your existing redirect. In that case, you can simply do something like this:
<input type="text" name="uFirst" class="form-control" placeholder="First name" value="<?= htmlentities($_GET["uFirst"]??"") ?>" required />
Encoding the values is very important. Not properly encoding values, especially from user input, can allow malicious users to craft values that break out of your HTML and alter the page, a vulnerability known as Cross-Site Scripting(or XSS, for short).
I have a form with some textbox that loads the data from the database. I have created also a button where I can update the data but currently it's not working and I don't have any clue why.
Here's my query:
<?php
include('connect.php');
if (isset($_POST['btnUpdate'])){
$query = "UPDATE users SET fname = '".$_POST['fname']."', lname = '".$_POST['lname']."' WHERE user_id = '".$_POST['id']."'";
$result = mysql_query($query);
if ($result) {
die("<strong>Updated</strong>");
} else {
die("<strong>Error ".mysql_error()."</strong>");
}
}
?>
Here's my form:
<form class="form-horizontal" role="form" action="" method="post">
<input type="hidden" name="id" value="<?php echo $row['user_id']; ?>"/>
<div class="form-group">
<label class="col-lg-3 control-label">First name:</label>
<div class="col-lg-8">
<input class="form-control" name="fname" type="text" value="<?php echo $row['fname'];?>">
</div>
<label class="col-lg-3 control-label">Last name:</label>
<div class="col-lg-8">
<input class="form-control" name="lname" type="text" value="<?php echo $row['lname'];?>">
</div>
<label class="col-md-3 control-label"></label>
<div class="col-md-8" >
<input type="button" name="btnUpdate" class="btn btn-primary" value="Save Changes">
<span></span>
<input type="reset" class="btn btn-default" value="Cancel">
</div>
</div>
</form>
I've tried everything but it won't update my database. It doesn't have any error whatsoever when I checked it on the browser. I'm running out of ideas. Anyone know what part of my code is wrong? I'm still a beginner to php and I cannot seem to understand what's wrong here. Any ideas how to solve this problem would be greatly appreciated. Thanks
Posting as a community wiki; I feel no rep should come of it.
<input type="button"> does not by default propagate POST. Therefore you either need to use a "submit" type:
Either <input type="submit"> or <button type="submit">.
References:
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/button
type
The type of the button. Possible values are:
submit: The button submits the form data to the server. This is the default if the attribute is not specified, or if the attribute is dynamically changed to an empty or invalid value.
reset: The button resets all the controls to their initial values.
button: The button has no default behavior. It can have client-side scripts associated with the element's events, which are triggered when the events occur.
You're also open to a serious SQL injection if your site is live or intended to go live.
You should start looking into switching over to either the mysqli_ or PDO api and with a prepared statement.
References:
http://php.net/manual/en/mysqli.prepare.php
http://php.net/manual/en/pdo.prepared-statements.php
https://en.wikipedia.org/wiki/SQL_injection
Good day all,
I have a question I looked it up everywhere and I still seem stuck
If I submit a form via post -> variable -> database and then redirect to another
page using header(location:page.php); in the time it takes to redirect and I
click on the submit button it still inserts duplicate data into the database
how do I prevent that from happening? as I read on tokens but I can't see how it
will work without processing my form data on another page and I don't want to
do that any help please ??
please see below html :
<form name="frmall"class="col s12" action="" method="post">
<!--basic info------------------------------------------------------------------------------------------------------------->
<div class="divider"></div>
<div class="section">
<h5>Basic Member Information</h5>
<div class="row">
<div class="input-field col s6">
<input id="first_name" name="txt_name" type="text" class="validate" value="<?php if(isset($_POST['btnContinue'])){echo $_POST['txt_name']; } ?>">
<label for="first_name">First Name</label>
</div>
<div class="input-field col s6">
<input id="last_name" type="text" name="txt_surname" class="validate"value="<?php if(isset($_POST['btnContinue'])){echo $_POST['txt_surname']; } ?>">
<label for="last_name">Last Name</label>
</div>
<div class="input-field col s6">
<input id="icon_telephone" type="tel" name="txt_number" class="validate"value="<?php if(isset($_POST['btnContinue'])){echo $_POST['txt_number']; } ?>">
<label>Telephone</label>
</div>
<div class="input-field col s6">
<input id="email" type="email" name="txt_email" class="validate"value="<?php if(isset($_POST['btnContinue'])){echo $_POST['txt_email']; } ?>">
<label for="email" data-error="wrong" data-success="right">Email</label>
</div>
<div class="input-field col s6">
<input id="idnumber" type="text" name ="txt_idnumber" class="validate"value="<?php if(isset($_POST['btnContinue'])){echo $_POST['txt_idnumber']; } ?>">
<label>ID Number</label>
</div>
</div>
<button class="btn waves-effect waves-light" type="submit" name="btnCancel">Cancel</button>
<button class="btn waves-effect waves-light" type="submit" name="btnContinue">Continue</button>
</div>
</Form>
PHP (please not its just for en example):
if (isset($_POST['btnContinue'])) {
$Conn->insert_main_member($name, $surname, $number, $idnumber, $email);
header(location:page.php);
}
So how do I prevent double submit without disabling the button ? please assist
Clear the post variable and place the header(...) in the right place (right after the db query execution).
The question is not very clear...
If you have problems with submitting the form multiple times and inserting the same values, you can do a check - either in your script (connect to database and check) or create a UNIQUE index in your database table - then the record will not be inserted, if it already exists.
If you have problems with too many people on the site and some data is inserted while it shouldn't and it should wait until something else is completed, then you can use LOCK TABLES command to send to your database.
If you have problems with uniquely identifying transactions, you can also use a token (e.g. a random hash generated before your form is submitted), for example as a hidden form field to send along with the data.
1st quick solution :
You could disable your submit button with javascript after 1st form submit to prevent any other submit before redirection...
2nd solution :
Add a token (generated server side) to your HTML form in a hidden input.
On form submit your token will be sent with other POST data.
Check your token server side before insert data into your database
Edit: Perhaps a sample of your code (server side + html form) could help us to give you a more appropriate answer.
Whenever I entered value first time and add record its added perfectly but whenever I refresh my browser by pressing F5 it shows message
"the page that you're looking for used information that you entered..." and insert duplicate record.
HTML code define below:
<?php include("Connection.php"); ?>
<form role="form" method="post">
<div class="col-md-6">
<div class="form-group">
<label>Type Name</label>
<input name="emptype" class="form-control" placeholder="Employee ID">
</div>
<div class="form-group">
<label>Type Description</label>
<input name="typedecs" class="form-control" placeholder="First Name">
</div>
</div>
<div class="col-md-12 text-right">
<button type="submit" name="addtype" class="btn btn-primary">Add Type</button>
<button type="reset" class="btn btn-default">Reset</button>
</div>
</form>
below is my PHP Code
<?php
$emptype=$_POST['emptype'];
$typedesc=$_POST['typedecs'];
if(isset($_POST['addtype']))
{
$query=mysql_query("insert into emptype(typename,typedesc)values('$emptype','$typedesc')")or die("<script>alert('Error');</script>");
echo '<script>showAlert();window.setTimeout(function () {HideAlert();},3000);</script>';
Does something i missing? Please Help.
suggestion: use mysqli_* or PDO instead of mysql_* functions, but you have written code in it so i gave the code also in it.
Just run a select query to check if the record already exists in database if exists then do not insert it again.
$query=mysql_query("SELECT * FROM emptype WHERE typename = '$emptype' AND typedesc='$typedesc') or die(mysql_error());
if (mysql_num_rows($query)<=0)
{
$query=mysql_query("insert into emptype(typename,typedesc)values('$emptype','$typedesc')")or die("<script>alert('Error');</script>");
}
One option could be to Test if the value is already in your database.
Source : example from PHP.net - mysql_query
// Formulate Query
// This is the best way to perform an SQL query
// For more examples, see mysql_real_escape_string()
$query = sprintf("SELECT * FROM emptype
WHERE typename='%s' AND typedesc='%s'",
mysql_real_escape_string($emptype),
mysql_real_escape_string($typdesc));
// Perform Query
$result = mysql_query($query) or die(mysql_error());
// Get num rows
$num_rows = mysql_num_rows($result);
// If $num_rows is False - It's not a duplicate
if(!$num_rows)
...
Consider using PDO PHP.net - PDO - mysql functions are depreciated.
i think it is because the php script (insert query) is at the same page of the HTML form, so when you refresh the page you tell the browser to call the php script again with previous data. so to prevent that separate the HTML form from the php so you code should be like:
1- HTML.php
<?php include("Connection.php"); ?>
<form role="form" method="post" action="Action.php">
<div class="col-md-6">
<div class="form-group">
<label>Type Name</label>
<input name="emptype" class="form-control" placeholder="Employee ID">
</div>
<div class="form-group">
<label>Type Description</label>
<input name="typedecs" class="form-control" placeholder="First Name">
</div>
</div>
<div class="col-md-12 text-right">
<input type="submit" value="submit">
</div> </form>
2- Action.php
<?php include("Connection.php");
$emptype=$_POST['emptype'];
$typedesc=$_POST['typedecs'];
if(isset($_POST['addtype']))
{
$query=mysql_query("insert into emptype(typename,typedesc)values('$emptype','$typedesc')")or die("<script>alert('Error');</script>");
echo '<script>showAlert();window.setTimeout(function () {HideAlert();},3000);</script>'; echo "<meta http-equiv='refresh' content='0;url=html.php'>";
?>
this will make html.php page call Action.php page when the submit button is pressed then the php script will be executed then it will redirect you to the html.php page again
I am creating a edit information page, but when i call out the data for password, it is encrypted. Is there a way i could decrypt it?
this is my codes,
<?php
require 'dbfunction.php';
$con = getDbConnect();
if (mysqli_connect_errno($con)) {
"Failed to connect to MySQL: " . mysqli_connect_error();
} else {
$result = mysqli_query($con, "SELECT * FROM admininfo where name = xyz");
while ($admininfo = mysqli_fetch_array($result)) {
?>
<div class="container">
<div class="row">
<center>
<h2>Edit Info Administrator</h2>
</center>
<form>
<div class="form-group">
<label class="col-sm-2 control-label">Name</label>
<div class="col-md-10">
<input type="text" class="form-control" value="<?php echo $admininfo['name']; ?>" name="name">
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Password</label>
<div class="col-md-10">
<input type="password" class="form-control" placeholder="<?php echo $admininfo['password']; ?>" name="password">
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Comfirm Password</label>
<div class="col-md-10">
<input type="password" class="form-control" placeholder="Confirm Password" name="confirmpassword">
</div>
</div>
<div class="form-group">
<div class="col-sm-10 col-sm-offset-2">
<input type="submit" value="edit account" class="btn btn-primary">
</div>
</div>
</form>
</div>
</div>
<?php } mysqli_close($con); } ?>
Currently the name is appearing, only the password is encrypted.
There is no way to tell, from the code you've provided, how the password is encrypted.
If it is done properly, then the password will be stored using a salt and a hashing algorithm and not any kind of reversible encryption. In that case, the answer will be "no".
You should never need to find out what a password is, only set a new one or compare a submitted one to the existing one. The latter case is handled by running the submitted password through the same hashing algorithm and comparing the two hashes.
Your admin probably shouldn't be setting a new password directly either, they should have access to a function that emails the user a one use only token that they can use to set a new password themselves.
This is a bad idea. Currently, you're showing $admininfo['password'] as a placeholder. This means its characters will be actually visible on the screen, even if your input is of type password. Anyone looking over your shoulder will be able to see it. Don't do this.
Passwords should be stored in the database only hashed and salted. There is a way to check whether a certain plaintext is the original password, but there is no way to decrypt the hash (other than brute force). This is done like this for obvious security reasons.
Have a look at password_hash() and password_verify().