I have a simple web-based database using php/mysql that I use to keep track of products leaving my stockroom.
The MySQL database has a bunch of tables but the two I'm concerned with are 'Requests' and 'Salesperson' which you can see below (I've omitted irrelevant information).
Requests
R_ID ... R_Salesperson
1 ... James
2 ... Bob
3 ... Craig
Salesperson
S_ID S_Name
1 ... James
2 ... Bob
3 ... Craig
In my head section I have the following script that dynamically populates a list of our sales staff names as you type them:
// Autocomplete Salesperson Field
$("#form_specialist").autocomplete("../includes/get_salesperson_list.php", {
width: 260,
matchContains: true,
//mustMatch: true,
//minChars: 0,
//multiple: true,
//highlight: false,
//multipleSeparator: ",",
selectFirst: false
});
aaand get_salesperson_list.php:
<?php
require_once "get_config.php";
$q = strtolower($_GET["q"]);
if (!$q) return;
$sql = "select DISTINCT S_Name as S_Name from Salesperson where S_Name LIKE '%$q%'";
$rsd = mysql_query($sql);
while($rs = mysql_fetch_array($rsd)) {
$cname = $rs['S_Name'];
echo "$cname\n";
}
?>
I also have some basic javascript input validation requiring a value be entered in the Salesperson field (script is in the head section):
<!-- Input Validation -->
<script language="JavaScript" type="text/javascript">
<!--
function checkform ( form )
{
// ** Validate Salesperson Entry **
if (form.form_specialist.value == "") {
alert( "Please enter Salesperson Name" );
form.form_salesperson.focus();
return false ;
}
// ** END Salesperson Validation **
return true ;
}
//-->
</script>
Aaaaanyway - the problem is I can't figure out how to reject any names not in the 'Salesperson' table. For example - if I were to type 'Jaaames' although it would initially suggest 'James' if I were to ignore it and submit 'Jaaames' this would be entered into the 'Requests' table. This is relatively annoying given my undiagnosed OCD and I'd rather not have to go through hundreds of requests every so often editing them.
I'd say you're taking the wrong approach here.
The Requests table should NOT be storing the salesperson's NAME, it should be saving their ID. The Primary Key of the Sales Person table.
Then, instead of using auto-complete to populate a TEXT input, I'd recommend using the same approach to populate a SELECT menu that uses the Sales Person's ID as a value.
This accomplishes the following:
your database becomes more normalized
it removes redundant information from the Requests table
removes the need to validate the Sales Person's name on the client side
By defining the S_ID as a foreign key to the Requests table, you ensure that ONLY entries in the Sales Person table can exist in the Requests table.
You could try binding an AJAX request to either the submit of the form or on changing your text field or maybe when the field loses focus.
For this example I am using jQuery:
$('input[name=salesperson').blur(function(){
//when the text field looses focus
var n = $(this).val();
$.post('a_php_file_that_checks_db_for_names.php', {salesperson:n}, function(data){
//post the name to a php file which in turn looks that name up in the database
//and returns 1 or 0
if (data)
{
if (data==='1')
{
alert('name is in database');
}
else
{
alert('name is not in database');
}
}
else
{
alert('no answer from php file');
}
});
});
You would also need a PHP file for this to talk to, an example being:
if (isset($_POST['salesperson']))
{
//query here to check for $_POST['salesperson'] in the db,
//fill in the blanks :)
$yourquery='select name from db where name=?';
if ($yourquery)
{
//looks like there were results, so your name is in the db
echo '1';
}
else
{
echo '2';
}
}
A bit of filling in the blanks required but you get the idea.
Hope this helps you out
EDIT:
A second, more elegant solution just came to mind - if you could get the list of salespersons and make a hidden form field for each, you could read them all into a JS object and test against it whenever the form field is changed. Unfortunately I don't have the time to write you an example but it sounds like a nicer way of doing it to me.
It seems like you're just using Javascript to validate your input - this isn't good as it will never run if your user doesn't support or disables Javascript. As suggested above, a server side validation would be much easier to check against the database. However, client-side validation is also helpful to have as a sort of first line of defense against bad input, since it's generally faster. I can't think of a great way to do this, but one way could be to populate a PHP array of salespersons, convert it to a javascript array, and then check to see if the form value is in the array. It's probably faster (and substantially less code) to just use server-side validation here.
Try adding some sort of validation before you put it on your database? I mean, inside the script that puts the request into the table?
The mustMatch option isn't working for you? I see it commented out.
Also, your script is vulnerable to a SQL injection attack. I realize this is an in-house application, but you never know when crazy is going to show up and ruin your day. At the top of your get_salesperson_list.php, right after you retrieve the query from $_GET, you could add something like this:
if (!preg_match("/^\w+$/", $q)) {
// some kind of error handling here, or at least a refusal to fulfill the request:
exit;
}
UPDATE: Sorry, I meant to say "exit" instead of "return". I do see that your script wasn't in a function. I have edited the above to account for that. Thanks for pointing that out.
Related
I'm writing a php program using mssql where I have a long query with many parameters and a quite big database. How could I solve that a parameter in the query only gets included when the corresponding form field is filled?
example:
SELECT * FROM Users WHERE UserdID='' AND Status='' AND ...
Lets say that this is an admin tool for seraching users but I only want to include those AND parameter='' sections where the corresponding form field has been filled.
I could check each form field and stich together the query but I feel like there is an easier and more elegant way.
Brother I hope you go with bellow algorithm
Create a Globel Variable for condition.
Check first input that value is not blank, if not blank then put into globel variable .
So on with other fileds.
After All input check the globel varriable content only those condtion which user submited.
Sample Example.
var a="";
if(txtUser!="")
{
a = a==""?"username= ".txtUser:"username= ".txtUser;
}
if(txtCountry!="")
{
a = a==""?"country= ".txtCountry:a." and country= ".txtCountry;
}
a variable for where condition
I was wondering if code I have written is open to attack.
$.ajax({
url: site_url+"/customer/update",
type: 'POST',
dataType: "json",
async: true,
data: {
'id':$('#id').val(),
'cuFirstname':$('#firstname').val(),
'cuLastname':$('#lastname').val(),
'cuPersonalnr':$('#personalnr').val(),
},
});
On the server it looks like this:
$this->db->where('cuID = '.$customerid);
$this->db->update('customers',$_POST);
So I'm thinking that maybe if someone could change the variables (cuFirstname, cuLastname, cuPersonalnr) in the data part of the ajax post, that they would be able to write sql-code there.
"update customers set cuFirstname = 'charlie', cuLastname = 'brown', cuPersonalnr = '7012230303' where cuID = 1000"
So if they changed cuLastname to something else it could look like this:
update customers set cuFirstname = 'charlie', [cuShouldnotbechanged] = 'brown', cuPersonalnr = '7012230303' where cuID = 1000
So my question is: Is it possible for an attacker to change those variable names, and if so, how?
The client can change any aspect of the AJAX call, simply by making their own HTTP request to your URL with their own parameters. So, yes, they could conceivably change any part of the request.
In your code, the question really boils down to "how does my database library handle the update?". You're doing the following:
$this->db->where('cuID = '.$customerid);
$this->db->update('customers',$_POST);
which is, presumably, building a query like:
UPDATE customers SET column1='some value', column2='some other value', ... WHERE cuID='whatever';
based on the keys and values of the $_POST array. To address your specific question about what happens if a client changes the keys n the $_POST array, it seems to me there are two possibilities:
if they enter a column name that does not exist, the database library is either going to ignore it (and update the stuff it is able to) or throw an error (because an UPDATE statement with a non-existent column name is an SQL error).
if they enter a column name that exists but that you did not intend to update, then that new column name will probably be used and updated (unless your database library has protection in place for that - some require you to explicitly state which columns can be updated in this way).
Can a user write SQL code into those variabiles? The answer is yes.
Is it open to attack? That entirely depends on your method of sanitization/SQL input.
You can use prepared statements such as PDO (properly) to prevent the possibility.
Otherwise sanitize/check the sent data:
It looks as the cuPersonalnr, should be numeric? check to make sure:
if (!is_numeric ($_POST['cuPersonalnr']))
exit(); //script stops, not a number
first name and last name, im assuming need to be alphanumeric only?
well create a check, or sanitize any other values that are not alphanumeric:
if(!ctype_alnum($_POST['cuFirstname'])) {
exit(); //script stops, contains unsafe characters
}
instead of exit() you can create an error variable, and return the error.
Basically i have a form where a studentID is inputted, i then want to check id the inputted studentID is in the database, if it is post the form to the next page. If not then display an error on the page where you input studentID
Don't really know where to start
Cheers
is this what you want?
<form id = "form" action = "./?page=markandfeedback" method = "post">
<br>
Mark for:
<INPUT id="stud" onkeypress="return isNumberKey(event)" type="text" name="stud" value="Enter Student Number">
<input type="submit" value = 'Continue'>
<?
$studID = $_POST['stud'];
$module2 = $_SESSION['module'];
$ex = $_POST['exer'];
$studerr = array();
$sql = 'SELECT * FROM `student`, `modules` WHERE `studentID` = '.$studID.' AND `moduleCode` = '.$_SESSION['module'];
$result = mysql_query ($sql);
// echo $_SESSION['module'];
if ($result == NULL) { // nothing found
echo "the student id you entered is not in the database";
}
else {
$_SESSION['student'] = $studID;
Header("Location: http://www.whereever.com/"); // send the browser where you want
exit();
}
?>
EDIT:
I went over the other answers. I assume you check for mysql injection properly. I recommend implementing AJAX AFTER everything works and is secure. The idea behind my solution was to solve the problem as simple as possible. If you want to make something fancy out of it you could:
generate the whole form via php and tell the user in the input field, that the id wasn't found
tell your Javascript to present the information in some fancy way
Use AJAX. Everybody loves forms with AJAX.
You could, as suggested, assume that the user entered a valid id. You would check on the "whereever" page wether the id is actually valid. If it weren't, you would simply send the user back to the form and tell the php to output an error message (maybe via get). This possibility is not usual, I am not sure if it has any advantages.
the mysql_num_rows hint is nice, too, if you don't want any data from the user. I thought you wanted to do something with the data because of the SELECT *.
Make a seperate controller that does the checking of the username.
Use ajax to check if user input is valid or not.
So you'll have something like this:
<input id="stud" onchange="checkStudentId(this)" />
<script>
function checkStudentId(inputElement) {
var id = inputElement.value();
$.ajax({
url: "test.html",
context: {id:id}
}).done(function() {
// Check the return result
});
}
</script>
Here is a reference to jquery ajax
http://api.jquery.com/jQuery.ajax/
You actually have to connect to the server in some fashion to figure out of the student exists. What you'd normally do in this situation is submit the form to the server and do validation server-side. If the student exists, you return the "next" page. If the student doesn't exist, then you return (or redirect to using a Location header) the same form again with an error message.
Another popular method would be to use an AJAX request to check asynchronously (which I see many other people are recommending). I'd only recommend this way if you're actually doing validation right as they've finished entering the student id and are showing an error message in real-time, effectively. In this way, AJAX is a nice-to-have to provide quick user feedback, but not a real solution. Keep in mind that regardless of this, you need to check for and handle this when the form is submitted anyway, or at the least, consider what will happen when the form is submitted with an invalid id.
People can bypass this check (EVERY request from the client side is considered hostile, you can't implicitly trust anything)
Another user may have deleted the student ID between the time the check was done and the form was submitted
There could be an error in your code that causes validation to falsely pass or not to recognize a negative response
Doing AJAX onsubmit makes no sense, because effectively you're doubling the amount of work by making the server handle two separate requests in a row. It's simply the wrong answer to the problem.
The biggest trouble with this implementation is the PHP code can quickly get quite hairy and hard to follow as you have everything mixed together.
This is where you probably start to tip over using PHP like a templating language (mixed php code and html markup) and start getting into using a framework where your views (the HTML) are decoupled from your PHP code (if you're using the very-populate MVC pattern, this code is called your controller -- precisely because it controls how the server responds). This is how any professional developer will work. Kohana, CakePHP, and Zend are all examples of fairly popular MVC frameworks, all of which are used professionally.
You can do this in two different ways
AJAX - make ajax call to your server and check the ID if its exist display the error else go to the next page
PHP - put a hidden input in your form and make the action of the form to the same page and check everything their and keep the values of the input fields is the $_POST['field_name'];
And you can make the action into another page and return back variable or make a session to hold the error message
Try this:
<?
if(isset($_POST['stud'])){
$studID = $_POST['stud'];
$module2 = $_SESSION['module'];
$ex = $_POST['exer'];
$studerr = array();
$host="hostname";//your db host
$user="user";//your db user
$pass="pass";//your db pass
$conn=mysql_connect($host,$user,$pass);
$sql = 'SELECT * FROM `student`, `modules` WHERE `studentID` = '.$studID.' AND `moduleCode` = '.$_SESSION['module'];
$result = mysql_query ($sql,$conn);
if(mysql_num_rows($result)>0){//the id was found in the DB, do whatever here...
echo $_SESSION['module'];
$_SESSION['student'] = $studID;
Header("Location: http://www.whereever.com/");//redirect to wherever
$error=false;
}
else{//id was not found
$error=true;}
}//end of isset
?>
<? if($error===true){?> <div> The id was not found.... </div> <?}?>
<form id = "form" action = "<? echo $_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI']; ?>" method = "post">
<br>
Mark for:
<INPUT id="stud" onkeypress="return isNumberKey(event)" type="text" name="stud" value="Enter Student Number">
<input type="submit" value = 'Continue'>
So what this does is: When the user hits submit, conects to the DB, and checks if the ID exists...if it does, then it redirects it to wherever.com (see comments) and if it don't an error messege will show up. Be sure to change the db variable values to your own ($host, $user, $pass).
wondering what the the best way to achieve something is.
To summarise, I have a form that I load by ajax which I use for to both update and insert new rows into a database. To determine whether it is an update or an insert I use the below code (updated forms use the mysql query to populate the form fields).
My code seems sloppy and not best practice. Are there any other suggestion on what would be the best way to do this?
<?
require_once("config.php");
$insert = false;
$update = false;
$targID = 0;
if(isset($_POST['targID'])){
$targID = $_POST['targID'];
$targRow = mysql_fetch_array(mysql_query("select * from events where eventid=$targID"));
$update = true;
}else{
$insert = true;
}
?>
<script type="text/javascript">
var insert = <? echo $insert; ?>+0;
var update = <? echo $update; ?>+0;
......javascript button events, validation etc based on inssert/update
</script>
You already know in the client whether it is an update or an insert, by the fact that you send or do not send the POST data item. So I would write JS in the original page to control the submit and what to do with the data that is sent back. It's difficult to write code without seeing the rest of the page, but at pseudo-code level, you could do the following:
use onsubmit() to catch original submit action
look to see if targID provided
if yes, send update request to server. When row data comes back, fill out form details and display form (you can 'show' a hidden DIV containing the form, for example)
if no - do you need to send anything? - just reveal an empty form (again, show a previously hidden DIV)
Hope this is useful in some way.
You should use native mySQL:
INSERT ... ON DUPLICATE KEY UPDATE
See:
http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
What's the point in determining that on the client side? Does it make any difference?
For the server side I'd use $targID passed from the hidden field. if it's greater than zero - update, otherwise - insert.
I have a PHP page that uses jQuery to let a user update a particular item without needing to refresh the page. It is an availability update where they can change their availability for an event to Yes, No, or Maybe. Each time they click on the link the appropriate jQuery function is called to send data to a separate PHP file (update_avail.php) and the appropriate data is returned.
Yes
Then when clicked the params are sent to a PHP file which returns back:
No
Then, if clicked again the PHP will return:
Maybe
It all works fine and I'm loving it.
BUT--
I also have a total count at the bottom of the page that is PHP code to count the total number of users that have selected Yes as their availability by simply using:
<?php count($event1_accepted); ?>
How can I make it so that if a user changes their availability it will also update the count without needing to refresh the page?
My thoughts so far are:
$var = 1;
while ($var > 0) {
count($day1_accepted);
$var = 0;
exit;
}
Then add a line to my 'update_avail.php' (which gets sent data from the jQuery function) to make $var = 1
Any help would be great. I would like to stress that my main strength is PHP, not jQuery, so a PHP solution would be preferred, but if necessary I can tackle some simple jQuery.
Thanks!
In the response from update_avail.php return a JSON object with both your replacement html and your new counter value.
Or to keep it simple, if they click "yes" incriment the counter, if they click No or maybe and their previous action wasn't No or Maybe decrease the counter.
Assuming your users are logged into the system I'd recommend having a status field in the user table, perhaps as an enum with "offline", "available", "busy", "unavailable" or something similar and use the query the number of available users whilst updating the users status.
If you were to do this you'd need to include in extend your methods containing session)start() and session_destroy() to change the availability of the user to available / offline respectively
The best way is the one suggested by Scuzzy with some improvements.
In your php, get the count from the database and return a JSON object like:
{ count: 123, html: 'Yes' }
In your page, in the ajax response you get the values and update the elements:
...
success: function(data) {
$("#linkPlaceholder").html(data.html);
$("#countPlaceholder").html(data.count);
}
...