PHP/MySQL Form submission troubles

I recently began a project to make an automated rating system for a radio series’ episodes. The premise is that it should work similarly to the “Kittenwars” page. As a prelude to this, I’ve started to try to implement a test system that uses all the same parts that will be necessary for the final completed page.

Here’s essentially how it is (supposed) to work:

  1. PHP generates two psuedo-random numbers.
  2. PHP contacts the server and selects two random items from the “game” table on the “test” database. Their IDs correspond with the previously picked random numbers.
  3. PHP contacts the server and echos the previously selected random items’ “points” for the user.
  4. PHP generates two forms. Each one, when sent, contacts the server and updates two numbers in the “storage” table. The first number sent by each form is the “winning” ID, the second number is the “losing” ID.
  5. The user clicks on one of the forms mentioned in the previous step.
  6. Before any of the above code has technically happened yet, PHP connects to the server. It selects the two numbers from “storage”, and updates the rows that the numbers correspond to in the “game” table – thus completing the cycle (since the “game” table is the one the user intends to influence).

Unfortunately, I’ve encountered a hurdle in development. When the user clicks on the submit button, the numbers the forms send to the server are not the numbers that the user saw, but instead the next numbers – the ones that are generated after the user clicks on one of the forms. This problem actually came up earlier in development, so I added the “storage” table with the idea that I could store the numbers it was supposed to have in the server (before they get wiped out by the next php rand action), and call them up for use after the page has been refreshed, but this hasn’t helped me at all.

I’m sorry if this description of the problem doesn’t suffice; I’m willing to provide any information on the MySQL database that’s necessary, and/or pictures of any stage of the process that y’all may want.

Here’s the PHP code (sloppy as it is) below. I don’t have any prior experience, so I have to admit that most of this comes from combining and changing tutorial code fragments. Thanks in advance for any help anyone can give; I’m at a dead end right now.

[php] <?php
mysql_connect(“localhost”, “user”, “password”) or die(mysql_error());
echo “Initial connection to the server was successful!
”;
mysql_select_db(“test”) or die(mysql_error());
$result = mysql_query(“SELECT * FROM storage WHERE ID = ‘1’”);
$row = mysql_fetch_assoc($result);
$storage = $row[‘numbers’];
$result = mysql_query(“SELECT * FROM storage WHERE ID = ‘2’”);
$row = mysql_fetch_assoc($result);
$storage2 = $row[‘numbers’];
$result = mysql_query(“UPDATE game SET Points=points + 1 WHERE ID = ‘$storage’”);
$result = mysql_query(“UPDATE game SET Points=points - 1 WHERE ID = ‘$storage2’”);
?>

<?php $test = rand(1, 3); $test2 = rand(1, 3); ?>
<?php

$result = mysql_query(“SELECT * FROM game WHERE ID = ‘$test’”);

while($row = mysql_fetch_assoc($result)){
echo “ID: “.$row[‘id’].”, Points:”.$row[‘points’]."
";

}

$result = mysql_query(“SELECT * FROM game WHERE ID = ‘$test2’”);

while($row = mysql_fetch_assoc($result)){
echo “ID: “.$row[‘id’].”, Points:”.$row[‘points’]."
";

}

?>

<?php echo ''; echo ''; echo ''; if (!isset($_POST['SubmitForm'])) { } else { $result = mysql_query("UPDATE storage SET numbers='$test' WHERE id = '1'"); $result = mysql_query("UPDATE storage SET numbers='$test2' WHERE id = '2'"); } ?> <?php echo '
'; echo ''; echo ''; if (!isset($_POST['SubmitForm2'])) { } else { $result = mysql_query("UPDATE storage SET numbers='$test2' WHERE ID = '1'"); $result = mysql_query("UPDATE storage SET numbers='$test' WHERE ID = '2'"); } ?>[/php]

What you’ve outlined seems complicated to me and I’m not 100% sure on what you mean.

[code]2) PHP generates two psuedo-random numbers.
3) PHP contacts the server and selects two random items from the “game” table on the “test” database. Their IDs correspond with the previously picked random numbers.
4) PHP contacts the server and echos the previously selected random items’ “points” for the user.
5) PHP generates two forms. Each one, when sent, contacts the server and updates two numbers in the “storage” table. The first number sent by each form is the “winning” ID, the second number is the “losing” ID.
6) The user clicks on one of the forms mentioned in the previous step.

  1. Before any of the above code has technically happened yet, PHP connects to the server. It selects the two numbers from “storage”, and updates the rows that the numbers correspond to in the “game” table – thus completing the cycle (since the “game” table is the one the user intends to influence).[/code]

Does that mean:

  1. Generate two random numbers.
  2. Select two items from the “game” table where the IDs are equal to the above random numbers.
  3. Output the above two items.
  4. A user submits one of two forms - one contains a winning ID, the other a losing ID.

What happens after that? Could you outline the process in a flow-chart sort of way:

User Visits Page with Forms --> Stage 1 Happens -> Stage 3 Happens etc…

The first three steps are just as you guessed; after that, things get a tad bit different; I’ll try to break the whole thing down as much as possible. I’m not sure this is quite the format you asked for, but I hope it will still be understandable and helpful.

“Step 1” is very complicated, and I don’t think it will make sense in its own right without knowing what happens afterwards, so I would recommend you start reading at “Step 4”, then go back to the top after you’ve read to step 6.

Step 1.
The user visits the page, “numbertest.php”. The page logs in to the server and selects the database we’ll be using for this, “test”.
[php] <?php
mysql_connect(“localhost”, “user”, “password”) or die(mysql_error());
echo “Initial connection to the server was successful!
”;
mysql_select_db(“test”) or die(mysql_error());
[/php]

Step 2.
Having selected the “test” database, it selects the first and second items in the “storage” table and records their values for future use in the “$storage” variables.
[php]$result = mysql_query(“SELECT * FROM storage WHERE ID = ‘1’”);
$row = mysql_fetch_assoc($result);
$storage = $row[‘numbers’];[/php]

Step 3.
It now updates the item in the “game” table that has an ID that is equal to the number that is stored in the first item in “storage”. The “game” table item’s “point” total is increased by 1.
[php] $result = mysql_query(“UPDATE game SET Points=points + 1 WHERE ID = ‘$storage’”);[/php]

The other, parallel code shown in my first post works the same way, except that it decreases the “game” table item’s “point” total, instead of increasing it.

Step 4.
The two random numbers are generated, as you mentioned. The numbers are equal to IDs in the “game” table, and it displays those items’ contents. Two forms appear, each displaying only a single submit button.

Step 5.
This is where things start to get a little bit complicated (everything else you said up to this point was correct).

The user clicks one of the submit buttons (we’ll say it’s the first button, as their code functions almost exactly the same). Button #1 has this code:

[php]<?php
echo ‘

’;
echo ‘’;
echo ‘’;

if (!isset($_POST[‘SubmitForm’])) {
} else {
$result = mysql_query(“UPDATE storage SET numbers=’$test’ WHERE id = ‘1’”);
$result = mysql_query(“UPDATE storage SET numbers=’$test2’ WHERE id = ‘2’”);

}

?>
[/php]
Button #1 submits “SubmitForm” through POST. As soon as “SubmitForm” is set, then it updates the first and second items in the “storage” table, filling the contents of the first item in “storage” with the first random number (the one that was generated in step 1), and putting the second number in the second item.

… or at least, that is what it is supposed to do. There’s a glitch in this process, which I will attempt to elaborate on after I’ve finished talking about the rest of the code.

Step 6.
The page (apparently) refreshes. Go to Step 1.

The Glitch

So far, the code looks workable (to me), but there’s a major hangup during step 5 of the process.

Button #1 (or #2) does submit two numbers through POST, but they don’t seem to be the right ones; sometimes it gives the server the opposite numbers.

After further study, I have concluded that my original explanation of the problem was wrong. In fact, the problem seems to come up every time the user switches buttons – as long as you keep pressing the same button, it will always work as intended, but when you switch from one button to the other, it initially gives an incorrect result (but it will begin to work correctly if you keep pressing it as the numbers change). Thus, you can consistently get the buttons to work incorrectly by alternating between them.

I know this is a convoluted explanation. I created a set of pictures to try to explain them, but unfortunately it seems that images in posts aren’t allowed on the forum right now. I’ll try to recreate them in text-based form so that they might still help you. The things in parentheses are the buttons.

Initial connection to the server was successful! ID: 2, Points:0 ID: 1, Points:0 ($test) ($test2)

ID 2 is on top, 1 is on the bottom. I’ll click the top button (for the top ID). I have the server start out at 0 in the “storage” table items’ contents, so it takes one click before the server seems to start recording user clicks.

Initial connection to the server was successful! ID: 2, Points:0 ID: 2, Points:0 ($test) ($test2)
An annoying artifact of my random number generation system is that it sometimes gives me the same IDs twice in a row. I haven't fixed this yet, and it bogs down the testing process. Hitting the top button again.
Initial connection to the server was successful! ID: 2, Points:0 ID: 1, Points:0 ($test) ($test2)
Back to square one here; clicking top button.
Initial connection to the server was successful! ID: 1, Points:-1 ID: 2, Points:1 ($test) ($test2)
As you can see, the top button actually works here. However, when I click the bottom button, it will produce the opposite of its intended effect and bring both numbers back down to 0.
Initial connection to the server was successful! ID: 1, Points:0 ID: 3, Points:0 ($test) ($test2)
ID 1 is now back at 0 points. If this code functioned properly, it would be at -2. When I click the top button, it will increment ID 3 by 1 point, though that's the opposite of what I intended.
Initial connection to the server was successful! ID: 3, Points:1 ID: 1, Points:-1 ($test) ($test2)

So it does seem I now have a better understanding of how the form submissions are going haywire. The only question is why it does this, and that’s one I can’t answer.

I hope this new post was able to shed a little light on the situation. I know my writing is often difficult to read, so if there’s anything that doesn’t make sense, please ask and I’ll try to explain it.

Thanks very much for your attention.

Still have no clue what yer trying to accomplish, and your description of some steps seem that they could be better implemented. In the end, I see it like a Like/Dislike System or a Yes/No Voting kind of thing

My Solution:

[php]<?php

// MySQL Connect
// MySQL Select

if(isset($_POST[‘game_id’]) && isset($_POST[‘kitten_id’])) {

// Submitting a result
// Validate ID's
if(empty($_POST['game_id']) || empty($_POST['kitten_id'])) {
	die('Kitten fail!');
} else {
	if(preg_match('/^[0-9]+$/', $_POST['game_id']) == 1 && preg_match('/^[0-9]+$/', $_POST['kitten_id']) == 1) {
		
		$game = "SELECT * FROM `games` WHERE `games`.`id`='" . $_POST['game_id'] . "'";
		$result = mysql_query($game);
		
		if(mysql_num_rows($result) == 1) {
			$game = mysql_fetch_array($result);
			
			if($game['ip'] == $_SERVER['REMOTE_ADDR'] && $game['winner'] == '') { // Security Checks
				
				// Update game
				mysql_query("UPDATE `games` SET `games`.`winner`='" . $_POST['kitten_id'] . "' WHERE `games`.`id`='" . $game['id'] . "'");
				
			} else {
				die('Void in the matrix!');
			}
		} else {
			die('Could not find game!');
		}
		
	} else {
		die('Invalid game ID / kitten ID!');
	}
}

}

$total_kittens_query = 'SELECT max(id) AS max FROM kittens';
$query_result = mysql_query($total_kittens_query);
$result = mysql_fetch_array($query_result);

$random_kitten_one = mt_rand(1, $result[‘max’]);
$random_kitten_two = mt_rand(1, $result[‘max’]);

while($random_kitten_one == $random_kitten_two) {
$random_kitten_two = mt_rand(1, $result[‘max’]); // Prevent duplicates
}

$query = “SELECT * FROM kittens WHERE kittens.id=’” . $random_kitten_one . “’ OR kittens.id=’” . $random_kitten_two . “’”;

$result = mysql_query($query);

if(mysql_num_rows($result) == 2) {
// Create a game
$game_query = “INSERT INTO games (kitten_one, kitten_two, winner, ip) VALUES (’” . $random_kitten_one . “’, '” . $random_kitten_two . “’, ‘’, '” . $_SERVER[‘REMOTE_ADDR’] . “’)”;
// Game table: id (auto_inc, int, 10), kitten_one (int, 10), kitten_two (int, 10), winner (int, 10), ip (varchar, 15)
$game_id = mysql_insert_id();

$kitten_one = mysql_fetch_array($result);
$kitten_two = mysql_fetch_array($result);

echo '<form action="?" method="post"><input type="hidden" name="game_id" value="', $game_id, '"><input type="hidden" name="kitten_id" value="', $kitten_one['id'], '"><input type="submit" value="Vote 4 Kitten One"></form>';
echo '<form action="?" method="post"><input type="hidden" name="game_id" value="', $game_id, '"><input type="hidden" name="kitten_id" value="', $kitten_two['id'], '"><input type="submit" value="Vote 4 Kitten Two"></form>';

} else {
die(‘Error in the matrix!’);
}[/php]

That’s how I would replicate a game similar to kittenwars. Let me know if that helps / doesn’t help / you need more help.

Thanks very much for the help, work, and attention.

I’ve set to work on trying to get this implemented, creating the tables to match the new code requirements. I created a “kittens” InnoDB table with a single default id field, and a “games” InnoDB table with the fields outlined in the comment.

The submit buttons show up, but so far they consistently bring up the “Kitten fail” error. When I temporarily commented out some of the security measures to see if I could get closer to the problem, I believe I ended up with the “Could not find game” error. I’m not sure why this is; I’m pretty sure I created the table correctly, and from the little I can tell the code looks fine.

You need to add several kittens to the database. And FYI, the kittens table would hold all of the information about that option - e.g. a short description, image path etc.

I added ten, and they do show up in the kittens.php source in the browser, but the game ID always returns 0:

<form action="?" method="post"><input type="hidden" name="[b]game_id[/b]" value="[b]0[/b]"><input type="hidden" name="kitten_id" value="2"><input type="submit" value="Vote 4 Kitten One"></form><form action="?" method="post"><input type="hidden" name="game_id" value="0"><input type="hidden" name="kitten_id" value="3"><input type="submit" value="Vote 4 Kitten Two"></form>

“auto_increment” is set to 1 on the “games” table, so that shouldn’t be a problem, but I’m not sure.

Is the ID field auto incrementing and primary key?

It seems to be, yes – according to Sequel Pro, my MySQL GUI client, this is the current create syntax for the “games” table:

CREATE TABLE `games` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `kitten_one` int(10) DEFAULT NULL, `kitten_two` int(10) DEFAULT NULL, `winner` int(10) DEFAULT NULL, `ip` varchar(15) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1;

To me kittenwars looks like a Hot Or Not Script. Since I didnt see a way to see anything really special about the whole script.

So I made a few scripts, using a simple system with sqlite :slight_smile:
[b]filename:[b] createdb.php


<?php
  // Create Database
  $sdb=sqlite_open('wih.sdb');
  sqlite_exec($sdb,'CREATE TABLE wih ( id INTEGER PRIMARY KEY, filename VARCHAR( 32 ), wins INTEGER, loss INTEGER, rating FLOAT )');
  sqlite_exec($db.'CREATE TABLE casts ( id TEXT UNIQUE NOT NULL, dt DATETIME, p1 INTEGER, p2 INTEGER )');
  $files=glob('D:\Downloads\MyPics\*.jpg');
  foreach($files as &$file)
  {
    $file=basename($file);
    sqlite_exec($sdb,"INSERT into wih (filename) VALUES('{$file}')");
  }
?>

Just some simple tables to illustrate the workings
And the builk of the script

[b]filename:[b] index.php

[code]<?php
//header(“Content-Type: text/plain”);
$sdb=sqlite_open(‘wih.sdb’);
if(isset($_GET[‘cast’]) && isset($_GET[‘id’]))
{
$cast=array_search($_GET[‘cast’],array(0,1));
$id=preg_match(’@^[a-f0-9]{14}.[0-9]{8}$@’,$_GET[‘id’])?$_GET[‘id’]:FALSE;
if($cast!==FALSE && $id!==FALSE)
{
$res=sqlite_query($sdb,“SELECT * FROM casts WHERE id=’{$id}’”);
$bout=sqlite_fetch_array($res,SQLITE_NUM);
$opps = array($bout[2],$bout[3]);
foreach($opps as $idx=>$opp)
{
$field=($cast==$idx)?“wins”:“Loss”;
sqlite_exec($sdb,“UPDATE wih SET {$field}={$field}+1 WHERE id=$opp”);
}
}
}
sqlite_exec($sdb,“DELETE FROM casts WHERE dt < datetime(‘now’,’-10 minutes’)”);
//$res=sqlite_query($sdb,‘SELECT COUNT() FROM wih’);
$max=intval(sqlite_single_query($sdb,'SELECT count(
) FROM wih’));
$p1=rand(1,$max);
while(($p2=rand(1,$max))==$p1);
$where=implode(’,’,array($p1,$p2));
$res=sqlite_query($sdb,“SELECT id,filename FROM wih WHERE id IN ({$where})”);
echo ‘

’;
do {
$cid=uniqid(null,true);
$ok=sqlite_exec($sdb,‘INSERT INTO casts (id,dt,p1,p2) VALUES (’’. $cid ."’,datetime(‘now’),{$p1},{$p2})");
} while(!$ok);
$cast=0;
while($row=sqlite_fetch_array($res,SQLITE_NUM))
{
echo <<<EOF EOF; $cast++; } echo '
' ?> [/code] You can easily change the html around, I used a simple table, 2 forms :) all processing done at the top. Notice, I didnt really see a need to keep a history of each bout/game. it just tabulates the wins/losses :) Notice the cleanup on line 20

the last script i used, was so i didnt have to move my images for this script, so was a quick hack script to pick up an image file from another folder on my system
[b]filename:[b] image.php


<?php
  $ipath='D:\Downloads\MyPics\\';
  $img=isset($_GET['img'])?(basename($_GET['img'])):'';
  $info=pathinfo($img);
  if(empty($img) || !file_exists($ipath.$img) || $info['extension']!='jpg')
  {
    header("HTTP/1.0 404 Not Found");
    die();
  }
  header('Content-Type: image/jpg');
  readfile($ipath.$img)
?>

Actually was a fun lil projet to do :slight_smile:

Hope you understand the code :slight_smile: Any questions feel free to ask

Bit of a breakthrough here.

Making the following change to the code made the page begin generating games:

[php]$game_query = “INSERT INTO games (kitten_one, kitten_two, winner, ip) VALUES (’” . $random_kitten_one . “’, '” . $random_kitten_two . “’, ‘’, '” . $_SERVER[‘REMOTE_ADDR’] . “’)”;
$result2 = mysql_query($game_query);[/php]

The page now generates a game every time new kittens are selected, as it is supposed to, but pressing the submit button returns a “Void in the matrix” error.

(I intended to highlight the code, but didn’t realize it wouldn’t happen; please disregard the bulletin board [b] in the last post.)

Not sure why that’s happening. Please could you check that the database contains the correct IP address and run a print_r of $game after:

[php]$game = mysql_fetch_array($result);[/php]

I hate to bog down the debugging and admit my ignorance, but by the database containing the correct IP address, are you referring to the IP addresses that are being stored in the “games” table, or should I look somewhere else?

[php]
Array ( [0] => 1 [id] => 1 [1] => 3 [kitten_one] => 3 [2] => 1 [kitten_two] => 1 [3] => 0 [winner] => 0 [4] => 192.168.1.64 [ip] => 192.168.1.64 ) Void in the matrix![/php]

The result looks fine to me, except that it isn’t recording the winner here. The IP address is correct in that that is my local address.

Silly mistake on my part!! I told you to put winner as an int yet then testing it’s value to be blank (a string).

Please replace:
[php] $game_query = “INSERT INTO games (kitten_one, kitten_two, winner, ip) VALUES (’” . $random_kitten_one . “’, '” . $random_kitten_two . “’, ‘’, '” . $_SERVER[‘REMOTE_ADDR’] . “’)”;[/php]
With:
[php] $game_query = “INSERT INTO games (kitten_one, kitten_two, winner, ip) VALUES (’” . $random_kitten_one . “’, '” . $random_kitten_two . “’, -1, '” . $_SERVER[‘REMOTE_ADDR’] . “’)”;[/php]

And:
[php]if($game[‘ip’] == $_SERVER[‘REMOTE_ADDR’] && $game[‘winner’] == ‘’) { // Security Checks[/php]
With:
[php]if($game[‘ip’] == $_SERVER[‘REMOTE_ADDR’] && $game[‘winner’] != -1) { // Security Checks[/php]

Try that :slight_smile: If it doesn’t work, get back to me and I’ll have another go!

Curiously, it doesn’t seem like much has changed:

[php]Array ( [0] => 2 [id] => 2 [1] => 6 [kitten_one] => 6 [2] => 5 [kitten_two] => 5 [3] => -1 [winner] => -1 [4] => 192.168.1.64 [ip] => 192.168.1.64 ) Void in the matrix![/php]

Is there any other debugging technique I can try, to see if I can get more information? I tried var_dump along with print_r, but it gave the same stuff that print_r does, just in a slightly different format.

Epic fail.

Please replace your if with:

[php]if($game[‘ip’] == $_SERVER[‘REMOTE_ADDR’] && $game[‘winner’] == -1) { // Security Checks[/php]

My appologies! I should have been checking if the winner value was -1 (not yet set). Oh dear!

…and it’s now functioning brilliantly!

My heartfelt congratulations to you; your work is essential to powering the site I had in mind, and it looks like it should be a painless way for anyone, at any level of experience to reproduce something like the Kitten War page.

Thanks very much for all the time you spent on this, and although this might not mean much, I’ll make sure you receive proper credit everywhere my copy of your code is used.

Sponsor our Newsletter | Privacy Policy | Terms of Service