So this is my early attempt at a Facemash style site in which the user will select one of two images, scoring a hit with the chosen image (the winner) and a miss with the unselected image (the loser) - both of which are recorded in a MySQL database.
The selected image is determined using javascript and uses jquery AJAX to notify a PHP script (backend.php) which updates the database.
This works absolutely correctly for updating the "hits" field. However, the "misses" are not consistently recorded. By this I mean that when the user clicks one image, the fact the other image has not been clicked is only sometimes shown in the database. As far as I can tell there is no pattern as to when the "miss" is and is not recorded, making it difficult to pinpoint where the problem lies.
I've checked the code over and over again and cannot understand why this is happening or what would be responsible for it, so I thought it would be best to post everything. I appreciate it's a lot to ask, but any explaination as to why I'm having this problem would be hugely appreciated, thanks.
<html>
<head>
<title>Facemash</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.js"></script>
</head>
<body>
<?php
// Make a MySQL Connection
mysql_connect("localhost", "admin", "admin") or die(mysql_error());
mysql_select_db("facemash") or die(mysql_error());
// Select two random people
$personA = rand(1, 28);
$personB = rand(1, 28);
// Ensure that it is not the same person
if ($personB == $personA) {
$personB = rand(1, 28);
}
// Function to return path of photo
function photoPath ($person){
$query = mysql_query("SELECT photo FROM people WHERE id=$person");
$result = mysql_fetch_row($query);
$result = $result[0];
echo $result;
}
?>
<!--Image for personA-->
<div id=photoA identity="<?php echo $personA ?>"><img src="<?php photoPath($personA);?>"/></div>
<!--Image for personB-->
<div id=photoB identity="<?php echo $personB ?>"><img src="<?php photoPath($personB);?>"/></div>
<script type="text/javascript">
$('#photoA').click(function() {
var hit = $('#photoA[identity]').attr('identity');
var miss = $('#photoB[identity]').attr('identity');
$.post ("backend.php", {winner: hit} );
$.post ("backend.php", {loser: miss} );
location.reload(true);
});
$('#photoB').click(function() {
var hit = $('#photoB[identity]').attr('identity');
var miss = $('#photoA[identity]').attr('identity');
$.post ("backend.php", {winner: hit} );
$.post ("backend.php", {loser: miss} );
location.reload(true);
});
</script>
</body>
</html>
backend.php:
<?php
// Make a MySQL Connection
mysql_connect("localhost", "admin", "admin") or die(mysql_error());
mysql_select_db("facemash") or die(mysql_error());
// Recieve id of winner from index.php
$winner = $_POST['winner'];
// Recieve id of loser from index.php
$loser = $_POST['loser'];
// Lookup hits for winner and update by adding 1
function updateHits ($winner) {
$query = mysql_query("SELECT hits FROM people WHERE id=$winner");
$result = mysql_fetch_row($query);
$result = $result[0];
$result++;
mysql_query("UPDATE people SET hits = $result WHERE id=$winner");
}
//Lookup misses for loser and update by adding 1
function updateMisses ($loser) {
$query = mysql_query("SELECT misses FROM people WHERE id=$loser");
$result = mysql_fetch_row($query);
$result = $result[0];
$result++;
mysql_query("UPDATE people SET misses = $result WHERE id=$loser");
}
updateHits($winner);
updateMisses($loser);
?>
Thanks again.
Couple things.
// Select two random people
$personA = rand(1, 28);
$personB = rand(1, 28);
// Ensure that it is not the same person
if ($personB == $personA) {
$personB = rand(1, 28);
}
This doesn't look like it will always guarantee they aren't the same person. The result of the second rand() could again return the same value as $personA
Instead of doing two queries to first select the misses and then increment it, why not make it one query?:
mysql_query("UPDATE people SET misses = misses + 1 WHERE id=$loser");
Lastly, in backend.php, instead of updating winners and losers even if you have only received one of the params, do an if else:
if($winner) {
updateHits($winner);
} else if ($loser) {
updateMisses($loser);
}
I think this will solve your problems.
As a matter of optimization, you should also combine your two POSTs into one.
Try changing your two functions to this and seeing if it will work. (If it doesn't I will just delete my answer.)
// Lookup hits for winner and update by adding 1
function updateHits ($winner) {
mysql_query("UPDATE `people` SET `hits` = hits + 1 WHERE `id`= '$winner'");
}
//Lookup misses for loser and update by adding 1
function updateMisses ($loser) {
mysql_query("UPDATE `people` SET `misses` = misses + 1 WHERE `id` = '$loser'");
}
This probably doesn't cause the problem, but you should only do one $.post and don't duplicate the same functionality in both click handlers.
JS:
$('#photoA, #photoB').click(function() {
var hit = $('#photoA[identity]').attr('identity'),
miss = $('#photoB[identity]').attr('identity');
$.post("backend.php", { winner: hit, loser: miss } );
location.reload(true);
});
Related
Sorry if I asked a dumb question, quite new to PHP. I wanted to select the next array value within the same page and the same id, as all of them are from the same id. Mind if I ask for any help on this code? Thanks!
<?php
//get the id from the view page / search page e.g. url?id=1
$_SESSION['id'] = $_GET['id'];
$id = $_SESSION['id'];
include "backend/connect.php";
$sqlquestion = "Select * from game_question where game_id_fk = $id";
$result = mysqli_query($conn,$sqlquestion);
if(mysqli_num_rows($result)<=0){
echo "<script>alert('No questions found!');</script>";
}
while($row = mysqli_fetch_array($result)){
$question[] = $row['game_question'];
$qid[] = $row['game_question_id'];
}
?>
<?php
$current_index = array_search($qid, $question);
$next = $current_index + 1;
$prev = $current_index - 1;
?>
<?php if ($prev > 0): ?>
Previous
<?php endif; ?>
<?php if ($next < count($question)): ?>
Next
<?php endif; ?>
This is the table schema of game_question
WARNING
Concatenating query params into query string may lead to SQL injection, take a look here
A simple way to do that is to implement some sort of pagination, in which each page is exactly 1 item long, and pass the current page as a GET param.
You can implement it as a LIMIT clause on your query, like this:
$pos = (isset($_GET['pos']) && $_GET['pos']) ? $_GET['pos'] : 0;
$sqlquestion = "
Select *
from game_question
where game_id_fk = $id
LIMIT 1 OFFSET $pos
";
Then you have to calculare previous and next position based on the $pos variable and add them in the links as a query param, like url.php?id=1&pos=3;
Note that this way positions starts at 0
I would take an approach of querying the DB only once, so i assume the amount of questions belonging to one id is not too huge.
This way you can retrieve all the results and then use some front end magic to display these results with next/prev functionality. I wrote a sample where jQuery has your questions, so its up to you how you want to display them.
You can also look at Bootstrap (https://getbootstrap.com/), it has some cool features, so you could get PHP to loop your questions and write the HTML elements, then Bootstrap would do its magic displaying it
I've also added parameter binding to your query, this will prevent some SQL injections and should always be used
<?php
//get the id from the view page / search page e.g. url?id=1
$id = $_SESSION['id'] = $_GET['id'];
include "backend/connect.php";
$stmt = mysqli_prepare($con, "SELECT * FROM game_question WHERE game_id_fk = ?");
mysqli_stmt_bind_param($stmt, "s", $id);
$result = mysqli_stmt_execute($stmt);
$questions = array();
if(mysqli_num_rows($result)<=0){
echo "<script>alert('No questions found!');</script>";
die;
}
while($row = mysqli_fetch_array($result)){
$questions[$row['game_question_id']] = $row['game_question'];
}
?>
<!-- HTML -->
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
var questions = <?php echo json_encode($questions) ?>;
$.each(questions, function (i, elem) {
// do your stuff
});
</script>
</head>
<body>
</body>
Here's an example of bootstrap tabs with prev/next buttons: https://codepen.io/techiegang/pen/QjdgJJ
I need to automatically refresh content from a mysql data table every 5 seconds, but showing only one distinct record at a time, going through every record in a endless loop.
I load news.php, that has this js :
<script type="text/javascript">
var auto_refresh = setInterval(function () {
$('#canvas').load('content.php').fadein("medium");}, 5000);
// refresh every 5 seconds
</script>
content.php has the db connection
$query_Recordset5 = "SELECT * FROM news";
$Recordset5 = mysql_query($query_Recordset5, $connection) or die(mysql_error());
$row_Recordset5 = mysql_fetch_assoc($Recordset5);
$totalRows_Recordset5 = mysql_num_rows($Recordset5);
As well as the fields echoed to the page.
I understand that you would have to create a counter and bring back one different record everytime, but I am having a tough time with it.
Thanks
If your table has an auto increment field (say "id"). You start by passing page.php and id of 0, so it will grab the auto increment field greater than 0, and then you pass that fields ID back through jquery. When you send it a second time it will not be included because you will be using the greater than sign.
The if num_rows == 0 checks to see if there are any fields, if none, then it will assume that the auto increment field you sent it is the last one, and then it will run the sql statement with the very first auto increment value.
<?php
// page.php
$id = (int) $_REQUEST['id'];
$sq = "select * from news where id > ".$id." order by id asc limit 0,1";
$qu = $con->query($sq);
if ($qu->num_rows == 0) {
$sq2 = "select * from news order by id asc limit 0,1";
$qu2 = $con->query($s2);
while ($fe = $qu->fetch_assoc()) {
echo $fe['id']."|".$fe['content'];
}
} else {
while ($fe = $qu->fetch_assoc()) {
echo $fe['id']."|".$fe['content'];
}
}
?>
<script>
$(document).ready(function() {
setInterval(function(){ updateNews(); }, 5000);
});
function updateNews() {
var id = 0;
id = $("#hidden-id").val();
$.get("page.php?id=" + id, function(data) {
// I use $.get so that I can split the data that it returns before populating
// the #canvas. This way we can strip off the first part which is the auto
// increment
var ref = data.split('|');
$("#hidden-id").val(ref[0]);
$("#canvas").html(ref[1]);
});
}
</script>
I have a javascript for loop that sends an array to an ajax page to update the mysql database.
I echo the result back to the original page and it echos as a success but when I check the db nothing has changed
my javascript for loop that sends the array
for(var m=0; m<array.length; m++){
$.post("update_page_positions.php",{page_ref:array[m][0], ref:array[m][12], menu_pos:array[m][1], sub_menu_pos:array[m][2], top_menu:array[m][3], pagelink:array[m][4], indexpage:array[m][5], hidden:array[m][6], page_title:array[m][7], page_desc:array[m][8], page_keywords:array[m][9], page_name:array[m][10], deletedpage:array[m][11]},
function(data,status){
alert("data="+data+" status="+status);
});
here is the php ajax page the updates the db
<?
include("connect.php");
$ref = $_POST['ref'];
$page_ref = $_POST['page_ref'];
$menu_pos = $_POST['menu_pos'];
$sub_menu_pos = $_POST['sub_menu_pos'];
$top_menu = $_POST['top_menu'];
$indexpage = $_POST['indexpage'];
$page_name = $_POST['page_name'];
$page_title = $_POST['page_title'];
$page_desc = $_POST['page_desc'];
$page_keywords = $_POST['page_keywords'];
$hidden = $_POST['hidden'];
$pagelink = $_POST['pagelink'];
$deletedpage = $_POST['deletedpage'];
$query = mysql_query("SELECT * FROM pages WHERE ref='$ref' AND page_ref='$page_ref'");
if(mysql_num_rows($query)==0){
mysql_query("INSERT INTO pages(page_ref, ref, page_name, menu_pos, sub_menu_pos, top_menu, link, indexpage) VALUES('$page_ref','$ref','$page_name','$menu_pos','$sub_menu_pos','$top_menu','$pagelink','$indexpage')");
}
if($deletedpage=="1"){
mysql_query("DELETE FROM pages WHERE ref='$ref' AND page_ref='$page_ref'");
mysql_query("DELETE FROM site_content WHERE ref='$ref' AND page_ref='$page_ref'");
}
else{
if(mysql_query("UPDATE pages SET menu_pos='$menu_pos', sub_menu_pos='$sub_menu_pos', top_menu='$top_menu', indexpage='$indexpage', page_name='$page_name', page_title='$page_title', desc1='$page_desc', keywords_list='$page_keywords', hidden='$hidden', link='$pagelink' WHERE ref='$ref' AND page_ref='$page_ref'")){
echo "updated!";
} else{
echo "error";
}
}
?>
the INSERT and DELETE functions are fine but the UPDATE returns a success statement but does not update the db.
Can anyone see what the problem is?
Posted as an answer because the comment was too hard to read:
Rather than echoing "updated", try echoing
"UPDATE pages SET menu_pos='$menu_pos', sub_menu_pos='$sub_menu_pos', top_menu='$top_menu', indexpage='$indexpage', page_name='$page_name', page_title='$page_title', desc1='$page_desc', keywords_list='$page_keywords', hidden='$hidden', link='$pagelink' WHERE ref='$ref' AND page_ref='$page_ref'"
(ie. the query you're trying to run).
See if that gives you some clues.
UPDATE reports success, but does nothing in case when its WHERE clause rejects all rows in updated table.
Maybe $page_ref identifier is correct (so DELETE works), but full $page_ref and $ref combination is not?
I have followed help located in this topic: Using infinite scroll w/ a MySQL Database
And have gotten close to getting this working properly. I have a page that is displayed in blocks using jquery masonry, in which the blocks are populated by data from a mysql database. When I scroll to the end of the page I successfully get the loading.gif image but immediately after the image it says "No more posts to show." which is what it should say if that were true. I am only calling in 5 posts initially out of about 10-15, so the rest of the posts should load when I reach the bottom of the page but I get the message that is supposed to come up when there really aren't any more posts.
Here is my javascript:
var loading = false;
$(window).scroll(function(){
if($(window).scrollTop() == $(document).height() - $(window).height()) {
var h = $('.blockContainer').height();
var st = $(window).scrollTop();
var trigger = h - 250;
if((st >= 0.2*h) && (!loading) && (h > 500)){
loading = true;
$('div#ajaxLoader').html('<img src="images/loading.gif" name="HireStarts Loading" title="HireStarts Loading" />');
$('div#ajaxLoader').show();
$.ajax({
url: "blocks.php?lastid=" + $(".masonryBlock:last").attr("id"),
success: function(html){
if(html){
$(".blockContainer").append(html);
$('div#ajaxLoader').hide();
}else{
$('div#ajaxLoader').html('<center><b>No more posts to show.</b></center>');
}
}
});
}
}
});
Here is the php on the page the blocks are actually on. This page initially posts 5 items from the database. The javascript grabs the last posted id and sends that via ajax to the blocks.php script, which then uses the last posted id to grab the rest of the items from the database.
$allPosts = $link->query("/*qc=on*/SELECT * FROM all_posts ORDER BY post_id DESC LIMIT 5");
while($allRows = mysqli_fetch_assoc($allPosts)) {
$postID = $link->real_escape_string(intval($allRows['post_id']));
$isBlog = $link->real_escape_string(intval($allRows['blog']));
$isJob = $link->real_escape_string(intval($allRows['job']));
$isVid = $link->real_escape_string(intval($allRows['video']));
$itemID = $link->real_escape_string(intval($allRows['item_id']));
if($isBlog === '1') {
$query = "SELECT * FROM blogs WHERE blog_id = '".$itemID."' ORDER BY blog_id DESC";
$result = $link->query($query);
while($blogRow = mysqli_fetch_assoc($result)) {
$blogID = $link->real_escape_string($blogRow['blog_id']);
$blogTitle = $link->real_escape_string(html_entity_decode($blogRow['blog_title']));
$blogDate = $blogRow['pub_date'];
$blogPhoto = $link->real_escape_string($blogRow['image']);
$blogAuthor = $link->real_escape_string($blowRow['author']);
$blogContent = $link->real_escape_string($blogRow['content']);
//clean up the text
$blogTitle = stripslashes($blogTitle);
$blogContent = html_entity_decode(stripslashes(truncate($blogContent, 150)));
echo "<div class='masonryBlock' id='".$postID."'>";
echo "<a href='post.php?id=".$blogID."'>";
echo "<div class='imgholder'><img src='uploads/blogs/photos/".$blogPhoto."'></div>";
echo "<strong>".$blogTitle."</strong>";
echo "<p>".$blogContent."</p>";
echo "</a>";
echo "</div>";
}
}
Here is the php from the blocks.php script that the AJAX calls:
//if there is a query in the URL
if(isset($_GET['lastid'])) {
//get the starting ID from the URL
$startID = $link->real_escape_string(intval($_GET['lastid']));
//make the query, querying 25 fields per run
$result = $link->query("SELECT * FROM all_posts ORDER BY post_id DESC LIMIT '".$startID."', 25");
$html = '';
//put the table rows into variables
while($allRows = mysqli_fetch_assoc($result)) {
$postID = $link->real_escape_string(intval($allRows['post_id']));
$isBlog = $link->real_escape_string(intval($allRows['blog']));
$isJob = $link->real_escape_string(intval($allRows['job']));
$isVid = $link->real_escape_string(intval($allRows['video']));
$itemID = $link->real_escape_string(intval($allRows['item_id']));
//if the entry is a blog
if($isBlog === '1') {
$query = "SELECT * FROM blogs WHERE blog_id = '".$itemID."' ORDER BY blog_id DESC";
$result = $link->query($query);
while($blogRow = mysqli_fetch_assoc($result)) {
$blogID = $link->real_escape_string($blogRow['blog_id']);
$blogTitle = $link->real_escape_string(html_entity_decode($blogRow['blog_title']));
$blogDate = $blogRow['pub_date'];
$blogPhoto = $link->real_escape_string($blogRow['image']);
$blogAuthor = $link->real_escape_string($blowRow['author']);
$blogContent = $link->real_escape_string($blogRow['content']);
$blogTitle = stripslashes($blogTitle);
$blogContent = html_entity_decode(stripslashes(truncate($blogContent, 150)));
$html .="<div class='masonryBlock' id='".$postID."'>
<a href='post.php?id=".$blogID."'>
<div class='imgholder'><img src='uploads/blogs/photos/".$blogPhoto."'></div>
<strong>".$blogTitle."</strong>
<p>".$blogContent."</p>
</a></div>";
}
}
echo $html;
}
I have tried using the jquery infinite-scroll plugin, but it seemed much more difficult to do it that way. I don't know what the issue is here. I have added alerts and did testing and the javascript script is fully processing, so it must be with blocks.php right?
EDIT: I have made a temporary fix to this issue by changing the sql query to SELECT * FROM all_posts WHERE post_id < '".$startID."' ORDER BY post_id DESC LIMIT 15
The blocks are now loading via ajax, however they are only loading one block at a time. The ajax is sending a request for every single block and they are fading in one after another, is it possible to make them all fade in at once with jquery masonry?
I seen your code in another answer, and I would recommend using the LIMIT functionality in MySql instead of offsetting the values. Example:
SELECT * FROM all_posts ORDER BY post_id DESC LIMIT '".(((int)$page)*5)."',5
This will just take a page number in the AJAX request and get the offset automatically. It's one consistent query, and works independent of the last results on the page. Send something like page=1 or page=2 in your jQuery code. This can be done a couple different ways.
First, count the number of elements constructed on the page and divide by the number on the page. This will yield a page number.
Second, you can use jQuery and bind the current page number to the body:
$(body).data('page', 1)
Increment it by one each page load.
Doing this is really the better way to go, because it uses one query for all of the operations, and doesn't require a whole lot of information about the data already on the page.
Only thing to note is that this logic requires the first page request to be 0, not 1. This is because 1*5 will evaluate to 5, skipping the first 5 rows. If its 0, it will evaluate to 0*5 and skip the first 0 rows (since 0*5 is 0).
Let me know any questions you have!
Have you tried doing any debugging?
If you are not already using, I would recommend getting the firebug plugin.
Does the ajax call return empty? If it does, try echoing the sql and verify that is the correct statement and that all the variables contain the expected information. A lot of things could fail considering there's a lot of communication happening between client, server and db.
In response to your comment, you are adding the html in this piece of code:
if(html){
$(".blockContainer").append(html);
$('div#ajaxLoader').hide();
}
I would do a console.log(html) and console.log($(".blockContainer").length) before the if statement.
I have a 3 step chained-select sequence, game -> battle -> winning side , which pulls all data from a MySQL database.
After some wandering on the internet, I found a compact jQuery script that performs wonderfully. However, I am at a loss as to how to allow for existing data: <option selected="selected"></option> using this script.
chained select javascript:
<script>
var ajax = new Array();
function getScenNumList(sel)
{
var game = sel.options[sel.selectedIndex].value;
document.getElementById('scenarioNumber').options.length = 0; // Empty scenario number select box
if(game.length>0){
var index = ajax.length;
ajax[index] = new sack();
ajax[index].requestFile = 'js/getPlayData.php?gameName='+game; // Specifying which file to get
ajax[index].onCompletion = function(){ createScenarioNumbers(index) }; // Specify function that will be executed after file has been found
ajax[index].runAJAX(); // Execute AJAX function
}
}
function createScenarioNumbers(index)
{
var obj = document.getElementById('scenarioNumber');
eval(ajax[index].response); // Executing the response from Ajax as Javascript code
}
function getNations(sel)
{
var scenNum = sel.options[sel.selectedIndex].value;
document.getElementById('victor').options.length = 0; // Empty nation select box
if(scenNum.length>0){
var index = ajax.length;
ajax[index] = new sack();
ajax[index].requestFile = 'js/getPlayData.php?scenID='+scenNum; // Specifying which file to get
ajax[index].onCompletion = function(){ createNations(index) }; // Specify function that will be executed after file has been found
ajax[index].runAJAX(); // Execute AJAX function
}
}
function createNations(index)
{
var obj = document.getElementById('victor');
eval(ajax[index].response); // Executing the response from Ajax as Javascript code
}
</script>
excerpt from the PHP database retrieval script (getPlayData.php):
$gameName = mysql_real_escape_string($_GET['gameName']);
$q = "SELECT a, b, c FROM table WHERE game='$gameName' ORDER BY num ASC";
$r = mysql_query($q);
echo "obj.options[obj.options.length] = new Option('#','');\n";
while ($row = mysql_fetch_row($r)) {
$string = mysql_real_escape_string(($row[0].' - '.$row[1])); // needed so quotes ' " don't break the javascript
echo "obj.options[obj.options.length] = new Option('$string','$row[2]');\n";
}
echoing the obj.options is the stock method this script was using. It seems ugly to me, but I don't know any javascript so I didn't want to fiddle with it.
The HTML is simple enough, just a table with a few empty <select> objects with IDs matching those in the javascript and onchange="getXXX(this)" calls.
My question is this: Everything works great for new records, but I'm at a loss as to how I can alter this to support marking one option from each select as selected, assuming I have that data in hand (ex: a user is editing an existing record) ?
Many thanks!
You can see this tutorial for creating an option that is selected as default. http://www.javascriptkit.com/javatutors/selectcontent.shtml One parameter in the option constructor dictate that whether the option is selected or not.
In the PHP file you will edit as follow:
$gameName = mysql_real_escape_string($_GET['gameName']);
$q = "SELECT a, b, c FROM table WHERE game='$gameName' ORDER BY num ASC";
$r = mysql_query($q);
echo "obj.options[obj.options.length] = new Option('#','');\n";
while ($row = mysql_fetch_row($r)) {
$string = mysql_real_escape_string(($row[0].' - '.$row[1])); // needed so quotes ' " don't break the javascript
if ($string ......)
echo "obj.options[obj.options.length] = new Option('$string','$row[2]', false, true);\n";
else
......
}