Why is my database not being updated when someone visits my website? - php

For some reason when a user comes to my site to play multiplayer the call to the php file is sent, but the database never adds a new player or updates their information.
php file is called with the following line of code from a javascript file:
xmlhttp.open('GET',"xml_http_request.php?mod0="+truckHeading+"&mod1="+newhtr[1]+"&mod2="+absRoll+"&lla0="+lla[0]+"&lla1="+lla[1]+"&lla2="+lla[2]+"&pid="+rCC+"&rangeCheck="+rangeCheck+"&ranger="+ranger+"&namely="+namely+"&message="+message+"&unLoader=false", true);
Here's the php code:
<?php
require("db1.php"); //for using live public database
//require("db.php"); //for using local database
$inserter=0;
//assign pid if have not already
$pid=$_GET['pid'];
if($pid=='false'){
$inserter=1;
$query="SELECT id FROM positioner";
$result=mysql_query($query);
$num_rows=mysql_num_rows($result);
$i=1;
while($row=#mysql_fetch_assoc($result)){
if($i!=$row['id']){ $pid=$i;break; } //take first available id
$i++;
}
if($pid=='false'){ $pid=$num_rows+1; } //if no hole in id list, take next one higher
mysql_free_result($result);
}
$unLoader=$_GET['unLoader'];
if($unLoader=='true'){
$ddb=dbq("DELETE FROM positioner WHERE id = '".$pid."' LIMIT 1;");
}else{
$dbMi=$_GET['dbMi'];
$mod0=$_GET['mod0'];
$mod1=$_GET['mod1'];
$mod2=$_GET['mod2'];
$lla0=$_GET['lla0'];
$lla1=$_GET['lla1'];
$lla2=$_GET['lla2'];
$rangeCheck=$_GET['rangeCheck'];
$namely=addslashes($_GET['namely']);
if($namely==''){ $namely='x'; }
$message=addslashes($_GET['message']);
$rangeCheck='true';
//only check range every x number of ticks (50, ~3 seconds)?
// , $rangeCheck is true first time
if($rangeCheck=='true'){
$ranger=array();
//get lat lon of all for determining who is in range
$query="SELECT id, lla0, lla1 FROM positioner WHERE id != '".$pid."' ";
$result=mysql_query($query);
//if distance < 10000, put id in ranger array
while($row=#mysql_fetch_assoc($result)){
//leave rangeCheck off for now
//$di=dister($row['lla0'],$row['lla1'],$lla0,$lla1);
//if($di<10000){
$ranger[]=$row['id'];
//}
}
mysql_free_result($result);
if(count($ranger)==0){
$rangerS='';
}else{
$rangerS=implode(",", $ranger);
}
//between rangeChecks get ranger array from js
}else{
$rangerS=$_GET['ranger']; // $rangerS: string(for inserting)
$ranger=explode(",",$rangerS); // $ranger: array(for looping)
}
//insert new row first time
if($inserter==1){
$idb=dbq("INSERT positioner (id,mod0,mod1,mod2,lla0,lla1,lla2,ranger,namely,message,model)
VALUES ('".$pid."', '".$mod0."', '".$mod1."', '".$mod2."', '".$lla0."', '".$lla1."', '".$lla2."', '".$rangerS."', '".$namely."', '".$message."', '".$dbMi."');");
}else{
//update the database with current model data and result of range check
$udb=dbq("UPDATE positioner SET mod0 = '".$mod0."', mod1 = '".$mod1."', mod2 = '".$mod2."', lla0 = '".$lla0."', lla1 = '".$lla1."', lla2 = '".$lla2."', ranger = '".$rangerS."', namely = '".$namely."', message = '".$message."', model = '".$dbMi."' WHERE id = '".$pid."' LIMIT 1;");
}
header("Content-type: text/xml");
echo '<markers>';
echo '<marker ranger="'.$rangerS.'" pid="'.$pid.'" />';
//loop through a number of times equal to number of id's in ranger array
foreach($ranger as $rang){
$query="SELECT mod0, mod1, mod2, lla0, lla1, lla2, namely, message, model FROM positioner WHERE id = '".$rang."' ";
$result=mysql_query($query);
while ($row=#mysql_fetch_assoc($result)){
echo '<marker mod0="'.$row['mod0'].'" />';
echo '<marker mod1="'.$row['mod1'].'" />';
echo '<marker mod2="'.$row['mod2'].'" />';
echo '<marker lla0="'.$row['lla0'].'" />';
echo '<marker lla1="'.$row['lla1'].'" />';
echo '<marker lla2="'.$row['lla2'].'" />';
echo '<marker namely="'.rawurlencode(stripslashes($row['namely'])).'" />';
echo '<marker message="'.rawurlencode(stripslashes($row['message'])).'" />';
echo '<marker dbMi="'.$row['model'].'" />';
}
}
echo '</markers>';
} //end if unLoader
//function for calculating distance between latlon pairs, for range check
/* not necessary for only a few visitors
function dister($lat1,$lon1,$lat2,$lon2){
$R=6378100;
$lat1*=pi()/180;
$lon1*=pi()/180;
$lat2*=pi()/180;
$lon2*=pi()/180;
$dLat=$lat2-$lat1;
$dLon=$lon2-$lon1;
$a=sin($dLat/2)*sin($dLat/2)
+cos($lat1)*cos($lat2)*
sin($dLon/2)*sin($dLon/2);
$c=2*atan2(sqrt($a),sqrt(1-$a));
$di=$R*$c;
$di=round($di,6);
return $di;
}
*/
?>

Some notes.
The "assign pid if have not already" block is tragic. You're grabbing the entire contents of the table, and then row-by-row checking to see if you found the right one. The code blindly assumes that the row count is going to match the id column when picking what the next pid should be. The proper thing to do (for MySQL) would be using an auto-increment column so that you don't need to worry about that mess.
Your DELETE FROM query contains an SQL Injection vulnerability. If pid is not the string 'false', it will never be validated. Someone can destroy the entire positioner table. How do you protect against it? Well...
You're using addslashes. This isn't a code smell, it's a code stench. addslashes has never, ever at any time in the entire history of computing been the correct thing to use*. I think you're looking for a real database escaping mechanism. Because you're using the atrocious "mysql" interface, you want mysql_real_escape_string.
lla1 and lla2? Those are the best and most descriptive names for columns you could come up with? I'm going to assume those are latitude/longitude pairs.
Once again, you have SQL injection in that SELECT.
And in that INSERT, you are possibly blindly trusting $rangerS. SQL Injection ahoy!
And in the UPDATE.
I'd also like to rant briefly about string 'true' and string 'false', but those are coming from bad Javascript. Consider having them submitted as 1 and 0 instead. Also, please, please consider using a modern Javascript library like jQuery instead of rolling your own Ajax bits. It will save you time and stress.
I think the core problem here is actually the initial pid check. I'm going to bet that you're always getting a new or incorrect pid back from the table, because the id is unlikely to perfectly match the row count. Then you're doing a blind no-error-check INSERT with the "new" pid, but if your indexes are designed properly, this will fail with a duplicate key error. Therefore, no updates. But this is just speculation. Other than the vulnerabilities here, I'm not sure I completely understand what's happening, and I'm not spotting anything obviously incorrect.
There's another possible problem here. I'm going to assume that pid means player ID from the context. Your code is blindly trusting that the request is coming from the player that owns that pid, but anyone can just make a request here with any valid pid and make moves for people as a result. I'm not sure you intended that.
* Okay, maybe someone found addslashes useful once or twice...

Related

How do I echo the contents of a MySQL table field?

I seem to be having trouble understanding the concept of how to properly use the information in a MySQL database using PHP/MySQLi. As I understand it, you generate a variable representing the connection object:
$connectionObject = mysqli_connect('serverString', 'userString', 'passString', 'databaseString');
then, generate a variable representing the query string you want to use:
$queryString = "SELECT rowName FROM tableName";
then, generate a variable representing the result object returned from a successful query:
$resultObject = mysqli_query($connectionObject, $queryString);
then, you use the fetch_assoc() function to generate an array from the result object and assign it to a variable:
$resultArray = myqli_fetch_assoc($resultObject);
then, you can use a while loop to (I have trouble with this one) to sort through the array and use the content of the row somehow:
while ($resultArray) {
echo $resultArray["rowName"];
}
Do I have this concept the wrong way, somehow, because its just not working for me, even to output the text content of a text-based CHAR(10) field with the contents of no more than: "BLAH".
The need to loop through the array to pick out the array item by name in the end anyway seems moot to me to begin with, but no matter where I look, I find the same concept.
My script code, minus a few key details, is:
if ($connectionObject=mysqli_connect("host0", "username0", "password0", "mysqldatabase0")) {
echo "Con";
}
if ($queryString="SELECT 'testdata' FROM 'testtable'") {
echo "Query";
}
if ($resultObject=mysqli_query($connectionObject, $queryString)) {
echo "Result";
}
if ($resultArray=mysqli_fetch_assoc($resultObject)) {
echo "Array";
}
while ($row=$resultArray) {
echo $row["testdata"];
print_r ($row);
}
mysqli_fetch_assoc returns an associate array of string representing the fetched row in the result set which is your $resultObject.
The problem is where you're using the while loop. You want to capture the returned associative array in a variable and access your data via that variable like follows:
while ($row = $resultArray) {
echo $row["rowName"];
}
To sort by rowName you can use the mysql order by clause in your query like follows which returns your results sorted by rowName:
$queryString = "SELECT rowName FROM tableName order by rowName";
Update after OP posted full code:
In your first if statement what would happen if the connection failed? You want to add some error handling there:
$connectionObject=mysqli_connect("host0", "username0", "password0", "mysqldatabase0"));
if (!$connectionObject) {
// exist out of this script showing the error
die("Error connecting to database " . mysqli_error($connectionObject));
} else {
// Don't really need this else but I'll keep it here since you already had it
echo "Con";
}
The problem is here You are using single quotes for column name and table name which are mysql identifiers. MySQL identifiers quote character is backtick not single quote.
Basically you need to use backticks if one of these identifiers are one of mysql reserved words (MySQL Reserved words), for other cases you don't need to use them.
Update your query:
if ($queryString="SELECT `testdata` FROM `testtable`") {
echo "Query"; // Leaving as is, not required
}
Lastly, an improvement. You want to add error handling here too:
if ($resultObject=mysqli_query($connectionObject, $queryString)) {
echo "Result"; // Leaving as is, not required
} else {
echo "Error executing Query " . mysqli_error($connectionObject);
}
Please note that when you use this script the error messages will be printed at the client i.e. when you use this script in a web application the errors will be shown in the user's browser. So you want to look into implementing logging and not printing them directly.
mysqli_fetch_assoc() returns one row as an associative array, of a mysqli_result object. Each time it is called, it returns the next row of results automatically and when used with a while loop, can be used to fetch an unknown number of result rows.
The $row['columnName'] is used to refer to the column. For example, if you had a person object with columns firstName, lastName, dateOfBirth, you could iterate through each person with a while loop as such:
while($row=mysqli_fetch_assoc($resultObject)){
$fname = $row['firstName'];
$lname = $row['lastName'];
$dob = $row['dateOfBirth'];
echo $fname . ' ' . $lname . ' ' . $dob;
}
This will echo details for a result returning an unknown amount of people.
Remember, calling the
if ($resultArray=mysqli_fetch_assoc($resultObject)) {
echo "Array";
}
before the while loop will skip the first result, so make sure the query returns multiple results when testing, as if you are only providing a resultObject containing one result, this might be why it isn't returning anything.
A better way to check if any results are returned is with the mysqli_num_rows($resultObject) function.
if(mysqli_num_rows($resultObject) > 0){
echo "Array";
}
Also not sure if it was just a typo but just to be sure, in your query you are selecting columnName not rowName:
$queryString = "SELECT columnName1(eg. firstName), columnName2(eg. lastName) FROM tableName";
I just recently started learning PHP, and the mysqli_fetch_assoc function confused me too, so I hope this helps!

Getting answers from a database

I am making an online test script where you can input the answers in the input elements. Once the test is submitted I want the database's answers to be compared with the inputted answers to say whether it is wrong or not, however the script I am using is not working! :S
Here is the problem!
In the database, I have 4 out of 50 ready answers set (not all yet) when I answer both 4 correct or wrong it returns them being incorrect. It lists all the answers, whether they're correct or incorrect in the page but it's not working correctly, no matter what inputs I do, it all the answers up to 49 say incorrect, then for some reason 50 says correct?...
Here is my script:
<?php
$con=mysqli_connect("localhost","dstsbsse","pass","user");
if (mysqli_connect_errno($con))
{
echo "ERROR - Failed to connect to MySQL Server. Please contact an Administrator at English In York: " . mysqli_connect_error();
}
//Set variables to hold output data and total score.
$output="";
$score=0;
//for-next loop. This means "Set n to value one. Every time through the loop (between {}) increase n by one. Do this while n is less than or equal to 50"
for($n=1;$n<=50;$n++)
{
$sql="SELECT a$n FROM answer WHERE 1";
// $sql="SELECT * FROM answer WHERE name='a$n'"; //sql is specific to your table of course - you will need to change this.
$result = $con->query($sql); // perform the query
$row = $result->fetch_assoc(); //load the result into the array $row
$key="a".$n; //concatenate to generate the $_POST keys
if($row['answer']==$_POST[$key]) //compare the data from the table with the answer
{
//answer is correct
$score++;
$output.="Answer $n is correct</BR>"; //add responses to the output string
}
else
{
$output.="Answer $n is incorrect</BR>";
}
}
$output.="Total score: $score/50"; //add the score
echo $output; //echo to screen.
Here is an example of one of the questions answer boxes:
<input type="text" name="a1" id="a1" required>
How can I fix this?
Fetching a query like:
SELECT a1 FROM answer
would return $row['a1'], instead of $row['answer']
So you should be using the column name, not the table one

How to loop my function based on query result

I wrote a function which makes a random id makeid(); Just to ensure the id is unique I have a SQL statement which checks if the id already exists.
$does_id_exist = mysql_query("SELECT COUNT(*) AS count FROM signups WHERE affid='$affid'");
if(mysql_num_rows($does_id_exist) == 1)
{
#loop function and perform query again
}
else
{
#insert record
}
So I'm having trouble with looping the function. How do I loop my function makeid() and perform the $does_id_exist check to ensure that each ID is unique.
--UPDATE-- Just to clarify- My code makes an id like YES#281E But before I INSERT this id into the users record. I just need to verify IF any other user already has this id. IF another user has this id that event must trigger my function to create a new id e.g. WOW!29E3 and again check the sql/query to ensure no other user has that id. Continue to loop if fails or end and INSERT if the id is available.
You can either just use a primary key on your database table, or something like this:
<?php
// the id to insert
$newId = null;
// populate with results from a SELECT `aff_id` FROM `table`
$currentIds = array();
// prepopulate
for( $i=0; $i<100000; $i++ )
{
$currentIds[] = "STRING_" + rand();
}
// generate at least one id
do
{
$newId = "STRING_" + rand();
}
// while the id is taken (cached in $currentIds)
while( in_array($newId, $currentIds) );
// when we get here, we have an id that's not taken.
echo $newId;
?>
Output:
STRING_905649971 (run time 95ms);
I'd definitely not recommend running the query repeatedly. Perhaps a final check before you insert, if your traffic volume is high enough.
Do not do COUNT(*), because you do not need to know how many rows is there (it should be 0 or 1 as you need Id unique), so even DB finds your row it will still be checking for the whole table to count. You really care if you got 1 row, so just select for row with that ID and this sufficient. You should also avoid using rand() - this does not help as you see and you cannot predict how many loops you can do before you find "free slot". use something predictable, like date prefix, or prefix incremented each day. anything that would help you narrow the data set. But for now (pseudocode!):
$id = null;
while( $id == null ) {
$newId = 'prefix' . rand();
mysql_query("SELECT `affid` FROM `signups` WHERE `affid`='${newId}'");
if( mysql_num_rows() == 0) {
$id = newId;
break;
}
}
Ensure you got DB indexed, to speed things up.
EDIT: I do agree that any cache would be useful to speed things up (you can add it easily yourself based on #Josh example), still, I think this is fixing at wrong place. If possible rethink the way you generate your ID. It does not really need to be auto increment, but something more predictable than rand() would help you. If your ID does not need to be easily memorable and it is not any security concern to have them sequential, maybe use numbers with other base than 10 (i.e. using 26 would use all digits + letters so you'd end with PREFIX-AX3TK, so string as you want, and at the same time you would easily be able to quickly generate next Id

Remove duplicates fetched from while loop

I am hoping to remove duplicate entries from an array that I am calling from a stored procedure with a while loop.
// Prepare stored procedure call
$sth = $dbh->prepare('CALL sp_get_recipes()');
// Call the stored procedure
$res = $sth->execute();
if ($res){
while( $row = $sth->fetchObject() ){
echo $row->Recipe; // I would like to echo this row just once.
echo '<ul class="recipe-body"><li>'.$row->Ingredient." ".$row->Quantity." ".$row->UoM.'</li></ul>';
}
// Close connection
$dbh = null;
}else{
$arr = $sth->errorInfo();
echo "Execution failed with MYSQL: " . $arr[0] . "\n";
die();
}
My understanding is my echo $row->Recipe; has to exist on it's own somehow. I've being looking into array_unique to echo the value just once but I can't seem to figure it out exactly. If someone could point me in the right direction it would be great.
UPDATE
Thanks for all the responses I have fixed up the stored procedure to return unique rows.
Create a temporary array before the while and store every Recipe in it which have been echoed. Before the echo check the temporary array for the current Recipe (if it contains don't echo it otherwaise echo & store it in the temporary array).
If you cannot change the database structure, which I would recommend, you could first store the information you get from the database query into objects (e.g. some kind of Recipe objects with an array of Ingredient objects) and then build your actual output.
If you can change the database structure or the way you query (if the latter already gives you what I'm about to recommend) you can have a table (assuming the database is relational) for the recipes with some kind of ID and another table for the ingredients of the recipes where each ingredient row also stores the ID of the recipe it belongs to.

How do I show a user's credit based on their session

I'm developing a simple LAMP app where users can credit their account using Paypal. I suspect this is a simple issue, but have spent quite a while experimenting to no avail and would appreciate any thoughts:
System has a user management system working fine using sessions, but I can't get it to display the current user's credit.
But I've been trying things along the lines of:
$result = mysql_query("
SELECT *
FROM users
INNER JOIN account
ON account.UserID=account.UserID
ORDER BY account.accountID");
while($_SESSION['Username'] = $row['Username'] )
{
echo $row['Username'];
echo $row['Credit'];
}
I suspect the while statement is invalid, but I want it to echo username and credit where the current session username = the username stored in the database.
Thanks so much for taking a look - very much appreciated.
Okay there is actually a lot wrong with your code that can not be fixed by you as you have obviously no knowledge of php at all.
But let me explain this so you can get a good understanding of what you did wrong:
First of all, your mysql statement is just wrong.
Why do you join a field on itself? You won't get the corresponding users <-> account rows because users is never actually joined.
In addition to that, if you want to fetch a single row (you only want one because you only want to echo the data of one user, fetching more is only heavier in resources), tell mysql to do that. A simple example would be "WHERE a="b" LIMIT 1 (select only row where a is equal to "b", return after finding the first).
Now, to read something from your query, you need to fetch the corresponding data.
You can do that by using mysql_fetch_assoc / mysql_fetch_array / mysql_fetch_object.
This would look something like this: $data = mysql_fetch_array($query);.
In this case, you don't need to use a while() loop as you only have one row. A while loop is only necessary if you want to work with more then one row.
The rest of your code would be correct, though you don't need to call echo twice. You can simply connect both variables with a ".": echo $row['Username'].$row['Credit'];.
If you want to insert a space in between, connect it with another dot: echo $row['Username']." ".$row['Credit'];.
while ($row = mysql_fetch_array($result, MYSQL_ASSOC))
{
if ($row['Username'] == $_SESSION['Username'])
{
echo $row['Username'];
echo $row['Credit'];
break; // I believe username is unuque.
}
}
But it's much better to get just 1 row from the table :
$result = mysql_query("
SELECT *
FROM users
INNER JOIN account
ON account.UserID=users.UserID
WHERE Username ='".mysql_real_escape_string($_SESSION['Username'])."'" );
if ($result && $row = mysql_fetch_array($result, MYSQL_ASSOC))
{
echo .....
}
You only have a mysql result, now you have to return that information as an associative array (or object)
while ($row = mysql_fetch_assoc($result)) {
if ($_SESSION['username'] == $row['Username']) {
echo $row['Username'];
echo $row['Credit'];
}
}
It appears as if you are using $_SESSION['username'] as a way to check user authentication on the site, much better to use a salted+hashed version of the username and possibly the login time (never include the password).
One thing that jumps out at me is that your query is joining on:
account.UserID=account.UserID
instead of:
account.UserID=user.ID
Also, this is not right:
while($_SESSION['Username'] = $row['Username'] )
The = sign is for assignment, not comparison, so you're actually setting the value of $_SESSION['Username'] to $row['Username']. Then, the expression is evaluated as a boolean (since it's within a while conditional), and if it's true once, it'll be true forever. Infinite loop city.

Categories