After submitting a payment form (credit cards, etc) to our payment gateway, we receive the "response_code" 1 when the payment is approved. We then use the following code to update a user's info in the database to reflect the approved transaction.
However, about every 1 out of 10 times, a user's info simply will not update even though the transaction returned an approved response. Is anything clearly wrong with this code? Or perhaps the response_code does not equal 1 for some reason?
<?php
session_start();
if ($_GET['response_code'] == 1)
{
require('scripts/global.php'); //connect to database
$email = $_SESSION['email'];
$level = 3;
$transaction_id = "" . htmlentities($_GET['transaction_id']);
mysql_query ("UPDATE `users` SET level = '$level', trans_id = '$transaction_id' WHERE `email` = '$email'"); //update user info
$error = "false";
}
else
{
$noerror = "true";
$message = "Sorry, an error occurred: " . htmlentities($_GET['response_reason_text']);
}
?>
Probably because there has been a session timeout? The WHERE uses the e-mail address, if this is not valid (not there) then you probably won't get an update.
Maybe you should check for transaction ID (or similar). I guess you've got something like that before the transaction starts?
edit: Also store if an error occurs, and try to store variables you need too. This makes it a lot easier to pinpoint the problem. Use a logfile for this for example.
Beyond the obvious security holes, you're not checking the results of your query. Try using mysql_error() and mysql_affected_rows() to see whether anything was updated. When either indicates something unusual, you'll also want to see the exact text of the query that ran. Things to check:
Was $email empty?
Did $transaction_id or $email have any apostrophes?
Do you have duplicate email addresses in the database?
Had the user already been set to level 3?
Did you lose connection to the database?
Did your script get called at all?
Related
EDIT: based on first reply I got below,I reworked my code and it now works... first checking the given email address to find the gamer id. Then checking the verfication state based on the gamer id. So if they change their email address in the future it will still know whether it's already been verified.
Below is my final code, (I've changed some name for items, so its not an exact copy/paste of my own code).
function email_not_verified ($email) { //check it's not already verified
include ('../connect.php'); // Include connect to database functions
$findUser= $db->prepare("SELECT game_id FROM players WHERE email=?");
$findUser->execute(array($email));
$user = $findUser->fetch();
if ( $findUser){
$veri= $db->prepare("SELECT sent_verification FROM players WHERE game_id=?");
$veri->execute(array($user["game_id"]));
$results = $veri->fetch();
$final = $results["sent_verification"];
}
if ($final == 1){
return TRUE;
}
else{
return FALSE;
}
}
Thanks again for the help.
Below, is my original question.
I'm trying to figure out a simple setup that stops a user repeatedly verifying their email address. As when they verify their email I'm awarding them a bonus of 300 credits for in store game purchases. I obviously don't want to keep dishing that out each time they follow their emailed verification link.
So I'm trying to run a check first, before the normal verification script is run.
But surprise, surprise: its not working...
I was trying to search my database for the email address with the verification field set to '1', I'd then see how many times it found this result. If it found it '0' times then that's fine to verify, if it found it once then its already been verified before.
function email_not_verified ($email) {
include ('../connect.php'); // connect to database
//check it's not already verified
$checkEmail= $db->prepare("SELECT * FROM players WHERE sent_verification=?, email=?");
$checkEmail->execute(array('1', $email));
$check2 = $checkEmail->rowCount();
if ($check2 = 1){
return TRUE;
}
else{
return FALSE;
}
}
I've been using
file_put_contents('results.txt',$check2);
to see the results of the code regardless of whether its putting out a TRUE or FALSE. But the result comes back as '0', even though I can see from looking at my database it should be '1'.
I'm not sure if there's a whole easier way to approach this, I keep trying to get my head around bind values but it's not yet sinking in... I'll continue to try.
Thanks for any help, guidance, pointing out the obvious... I feel like I've taken the wrong path with my script but can't think how else to approach it...
Cheers
Jon
Your if statement is wrong. You're using the assignment operator instead of comparison. This doesn't matter though because rowCount isn't always reliable, which is probably where the actual problem is. What you need to do is fetch the first row and see if you get a row back.
However, you probably don't want to attach this to e-mail verification. When users change their e-mail address, you will want to verify that new address and you probably don't want to give them 300 more credits each time they do. Otherwise, someone could programmatically change their e-mail address over and over again, creating a lot of credits for themselves.
I would separate out the 300 free credits as a coupon or something that can only be used once per account. On e-mail verification, if that coupon hasn't already been used up for that account, use it and mark it as such in your database. This could be done simply by adding another column for new_account_bonus_credits or something.
I am adding some server-side form validations (using php) in case one of the users of my site has javascript turned off. On one form, there are 10 separate input fields that can be changed. Could someone please tell me which protocol will use less system resources? In the first, I write some mySQL variables to check the user's current settings, and compare these with the posted settings. If all 10 posted values are identical to the current values, don't UPDATE database, else UPDATE the database:
$login_id = $_SESSION['login_id'];
$sql1 = mysql_fetch_assoc(mysql_query("SELECT value1 FROM login WHERE login_id =
'$login_id'"));
$sql1a = $sql1['value1'];
// Eight More, then
$sql10 = mysql_fetch_assoc(mysql_query("SELECT value10 FROM login WHERE login_id =
'$login_id'"));
$sql10a = $sql10['value10'];
$Value1 = $_POST['Value1'];
// Eight More, then
$Value10 = $_POST['Value10'];
//Other validations then the following
if (($sql1a == $Value1)&&($sql2a == $Value2)&&.......($sql10a == $Value10)) {
echo "<script>
alert ('You haven't made any changes to your profile');
location = 'currentpage.php';
</script>";
}
else {
$sqlUpdate = mysql_query("UPDATE login SET value1 = '$Value1',....value10 = '$Value10'
WHERE login_id = '$login_id'");
echo "<script>
alert ('Your profile has been updated!');
location = 'currentpage.php';
</script>";
}//End php
OR is it less expensive to just use the user-posted values (keep the $_POST variables) and avoid checking with the comparison line: (($sql1a == $Value1)&&($sql2a == $Value2)&&.......($sql10a == $Value10)) and just go right to
//Other validations then the following
$sqlUpdate = mysql_query("UPDATE login SET value1 = '$Value1',....value10 = '$Value10'
WHERE login_id = '$login_id'");
echo "<script>
alert ('Your profile has been updated!');
location = 'currentpage.php';
</script>";
Thanks for any input on this!
If I understand correctly, your question is whether it's OK for performance to check the profile for modifications. For me, after I've checked your code, this is about much more than just performance...
Let's start with the performance: AFAIK MySQL queries are slower than basic PHP comparisions, that's true - but on this scale, I really don't think it matters much. We're talking about two very basic queries which won't handle a lot of data.
Let's think about what the end user will see (UX): in the second scenario, the user will not have the most exact feedback telling him/her that no modification has been done. On a profile modification screen, I suppose that might not be intentional, so I would tell that we haven't modified anything. (Also, performing an unnecessary UPDATE query is not the most elegant.)
#aehiilrs is right, please pay attention to that comment. This style of MySQL usage is particularly bad for security - if you keep going with this, you will create a lot of security holes in your PHP code. And those are really easy to discover and exploit, so please, have a good look on the alternatives, starting with PDO as mentioned. Any good PHP book out there will show you the way. You can also have a look at a great Q/A here on StackOverflow: How can I prevent SQL injection in PHP?
I wonder whether it's a good idea to try to update the user interface like you did - I would strongly prefer loading another PHP without any <script> magic in the output. In the result PHP, you can always display something like a CSS-styled statusbar for displaying info like that.
I'm writing some data to a database using php. 99% of the time, the data is correctly written to the database. But sometimes, blank data is being inserted into the database. I dont think its a issue with my code, since I can write the data to the database most of the time.
If the server on which the database resides have a slow internet connection, or if the user have a slow internet connection in their pc, can this happen?
Actually there is a slight mistake..Seems like the data that gets blank, comes from a session variable. How can be the session variable get blanked at some time ?
This is the code by which the data get stored into the session variable:
if(!preg_match('/^[a-zA-Z0-9._\-]+#[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/', $email))
$count = 2;
if(!preg_match('/^[A-Za-z0-9]{6}+$/',$key))
$count = 2;
if(!$count)
{
$result = mysql_query("SELECT * FROM test WHERE verify = '$key' AND email = '$email'");
$count = mysql_num_rows($result);
if($count == 1)
{
$row = mysql_fetch_row($result);
$_SESSION['id'] = $row[0];
$_SESSION['name'] = $row[1];
$_SESSION['email'] = $email;
$_SESSION['pass'] = $row[3];
$_SESSION['key'] = $key;
mysql_close();
}
}
When it happens, all the 5 variables id, name, email, pass and key, becomes blank. Email, and Key is not taken from the Database. The key field contains only alphanumeric content. So is there a way the data taken from the database as well at the GET variables to go blank? ( but even then $count should 1). Because, only if $count is 1, can the data be written to the new table ( where it get blanked )
There are 2 forms. When the user completes the first form, that data is stored in a table test, and a verification mail is sent to them. From the verification link, i find out their key and email, and check the table test, to see whether they are valid. If they are valid ( that means $count is 1 ), then a new form is displayed to the user, where they are asked to enter few more details. Then all the data ( this new data, and also the data that was written to the table test ), shall be written to a new table.
This is where things go wrong. The new data is written perfectly to the new table. But the old data, that was stored in the table test, and copied to the session variable, becomes blank sometimes. I have posted its code above, showing how the session variables are set.
It shall be helpful if someone could point out my mistake, if its something wrong in my code.
Programmers have at least five tactics to make sure data gets written to a database.
Check the content of variables for sanity before writing.
Design the database to reject bad data.
Trap errors. All of them.
Read back what you just wrote.
A verbose mode that writes to a log file.
I have a bit of an issue with my code.
I'm making an administrative panel for users to add things to the database. On occasion, they might try to save data without changing it (open a dialog, click save without changing anything). This, of course, will make mysql_affected_rows() return '0' when checking to see if the UPDATE query worked.
Is there another query to make that will always UPDATE regardless of whether the data is the same or not (or can I modify a simple UPDATE query to always update)?
EDIT
This is for users who don't have programming experience. Of course you wouldn't want to update if there's no reason to, but when a user tries to update and it doesn't happen I end up showing a failure message. Rather than there being something wrong, its just it doesn't need to be updated. I need a way to show the user that, instead of a generic 'failure' message. If it failed for another reason, I still need to know.
From the MySQL Documentation:
If you set a column to the value it currently has, MySQL notices this
and does not update it.
Instead of checking mysql_affected_rows, just check to see if the query was successful:
if(!mysql_query("UPDATE ..."))
{
//failure
}
else
{
$verification = mysql_query("SELECT ROW_COUNT() as rows_affected");
$row = mysql_fetch_row($verification);
$rows_affected = $row[0];
if ($rows_affected > 0)
{
//update was performed
}
else
{
//no update was needed
}
}
Here's a situation, i have a list of support tickets that when you click the title of the ticket takes you to a page that displays the ticket in more detail. If uses URL GET variables to query the database. I've taken SQL injection into account but what if someone modifies the url to an id that doesn't exist? whats the best way to deal with that?
Thanks,
Jonesy
If the ID does not exist, send a 404 - Not Found header along with a nice error page telling the user that it wasn't found.
You probably have to make a page handling unsuccessful searches anyway; just route it in there. Then you can help the user to find what (s)he searches in a consistent way, provide cues and "most-searched-after" and what not.
This may seem too simple, but you should always validate your GET (or POST) variable before doing anything with them. In your case, just verify that the ID exists in the database. If it doesn't, inform the user.
You should always check if your query returned anything. If it returned 0 rows, the ID doesn't exist.
<?php
$result = mysql_db_query("your query", $link);
$num_rows = mysql_num_rows($result);
if($num_rows < 1) {
// row with that id doesnt exist
// do whatever you want
} elseif($num_rows > 1) {
// you have problem with your ids in db
} else {
// everything went fine
// do your thing here
}
?>
Check if the ticket exists; if not, react accordingly. What "react accordingly" means is determined by your business logic: create a new ticket? raise an error? take the user to a list of available tickets?
An example using the old mysql extension for brevity:
$sanitized_numeric_id = (int) $_GET['ticket_id']; // assuming id is numeric
$query_resource = mysql_query('SELECT `somecolumn`, `column2`, `othercolumn`
FROM `tickets`
WHERE `id`= ' . $sanitized_numeric_id);
if (mysql_num_rows($query_resource) > 0) {
// the ticket exists, do something with it
} else {
// the ticket doesn't exist, react accordingly
}