I have been trying to figure this out, I want to show preloader only once per visit. How can I do that?
Current code:
$(window).on('load', function() {
$('#status').fadeOut();
$('#preloader').delay(350).fadeOut('slow');
$('body').delay(350).css({'overflow':'visible'});
})
Could you try the sessionStorage
if ( ! sessionStorage.getItem( 'doNotShow' ) ) {
sessionStorage.setItem( 'doNotShow', true );
$('#preloader').delay(350).fadeOut('slow');
} else {
$('#preloader').hide();
}
Or take a look on this link How to show website preloader only once
No cookie whether session or persistent will provide a reliable solution to this problem. The only way I can see doing this properly would be to record the ip address of the visitor and check to see if that record matches one in a table:
If it doesn't, load the preloader.
If it does, don't load the preloader.
The only possible problem to this is people periodically clear the temp website data they collect so I would implement a timed record system and set it to a reasonable value like 30 days so if they haven't visited your site in 30 days we will presume they have cleared their cache and they will get the preloader, that would change the criteria to;
If visitor is new, load preloader
If visitor is old but less than 30 days, don't load preloader
If visitor is old and more than 30 days, delete record, create new record, load
preloader
Code example below;
#1: Detect IP
<?php
function myIp() {
$client = #$_SERVER['HTTP_CLIENT_IP'];
$forward = #$_SERVER['HTTP_X_FORWARDED_FOR'];
$remote = $_SERVER['REMOTE_ADDR'];
if(filter_var($client, FILTER_VALIDATE_IP))
{
$ip = $client;
}
elseif(filter_var($forward, FILTER_VALIDATE_IP))
{
$ip = $forward;
}
else
{
$ip = $remote;
}
return $ip;
}
$my_ip = myIp();
global $my_ip;
?>
#2: Operations
<?php
// Set preloader status
$play_preloader = "no";
// Check visitor ip records for current ip
$preloader_one = "select ip from preloader where ip='$my_ip'";
$connect_preloader_one = mysqli_query($con, $preloader_one);
$rows_preloader_one = mysqli_num_rows($connect_preloader_one);
// If no record exists, create a new one
if ($rows_preloader_one == 0) {
$preloader_insert = mysqli_prepare($con, "insert into preloader (ip) values (?)");
mysqli_stmt_bind_param($preloader_insert, "s", $my_ip);
mysqli_stmt_execute($preloader_insert);
$play_preloader = "yes";
// If records exist, find records older than 30 days
} else {
$preloader_two = "select ip,date from preloader where ip='$my_ip' and date < DATE_SUB(now(), INTERVAL 30 DAY)";
$connect_preloader_two = mysqli_query($con, $preloader_two);
// If records older than 30 days found
$rows_preloader_two = mysqli_num_rows($connect_preloader_two);
if ($rows_preloader_two > 0) {
// Delete old records
$preloader_delete = "delete from preloader where ip='$my_ip' and date < DATE_SUB(now(), INTERVAL 30 DAY)";
$preloader_delete_query = mysqli_query($con, $preloader_delete);
// Add new record
$preloader_insert = mysqli_prepare($con, "insert into preloader (ip) values (?)");
mysqli_stmt_bind_param($preloader_insert, "s", $my_ip);
mysqli_stmt_execute($preloader_insert);
$play_preloader = "yes";
// If records exist but no records are older than 1 month
} else {
$play_preloader = "no";
}
}
// Preloader
if ($play_preloader == "yes") {
$preloader = "
enter you html/js/css code for the preloader here
";
} else {
$preloader = "";
}
?>
Now save all the above code in a php file then reference it in your html and then call $preloader;
<html>
<head>
<?php include_once ('mypreloader.php'); ?>
</head>
<body>
<?php echo $preloader; ?>
</body>
</html>
This code has been tested on a running server and is working.
Related
I have a form where different users can update data. I have implemented a write protection script with AJAX to avoid conflicts if more then one user is working in the form. As i do not know it better ;) i have solved this in that way:
If the user open form the related user_id and timestamp will be updated in my SQL table for the specific form ID. With AJAX i check every 3 seconds if this user is still on the form and do a update of the timestamp. If another user is opening the form in parallel, i check if this timestamp is older then 10 seconds. If this is true i update the SQL table with the new user_id and timestamp every 3 seconds. If the timestamp from the first user is not older then 10 seconds i just lock the form by adding a overlay with a high z-index. So the user can see the infomation but can not change it. I also show a information that this form is currently locked.
This sounds simple and is working ... more or less...
Here comes my problem:
It seems like that due to for me some unknown reason the SQL table does not gets updated every 3 seconds. (Edit:) I is working correctly sometimes for a longer time. But sometimes but not very often the SQL update is not initiated within 9 seconds (this is 3 tries). I added my script bellow, may be my routine is not optimal for my needs? Would be happy if you can help me to optimize it to avoid those update delays (hicks).
I am working local. Using the XAMPP Control Panel v3.2.4. PHP Version 7.4.6
Code in my frontend page:
<script type="text/javascript">
var auto_refresh = setInterval(
function() {
$('#login')
.load('ajax-audit_execute_login.php?audit_id=<?= $audit_id ?>&user_id=<?= $user['id'] ?>');
}, 3000); // refresh every 3000 milliseconds
</script>
<div id="login">
<?php
// Check if someone is logged in into that form
$statement = $pdo->prepare("SELECT login_at, login_by FROM audit WHERE id = :id");
$result = $statement->execute(array(':id' => $audit_id));
$login = $statement->fetch();
// Calculate the tim ebetween the now and the latest login timestamp
$ts2 = strtotime(date("Y-m-d H:i:s"));
$ts1 = strtotime($login['login_at']);
$seconds_diff = $ts2 - $ts1;
// If its the same user who locked the form latest do just an update of the timestamp
if ($login['login_by'] == $user['id']) {
$query = "UPDATE audit
SET login_at = :login_at,
login_by = :login_by
WHERE id = :audit_id";
$pdoResult = $pdo->prepare($query);
$pdoExec = $pdoResult->execute(array(":login_at" => date("Y-m-d H:i:s"), ':audit_id' => $audit_id, ':login_by' => $user['id']));
$locked = 0; // Form is not locked
} else {
// If its another user check if the timestamp is older then 10 seconds
if ($seconds_diff > 10) {
// The timestamp is older then 10 seconds. Update the SQL data for new user.
$query = "UPDATE audit
SET login_at = :login_at,
login_by = :login_by
WHERE id = :audit_id";
$pdoResult = $pdo->prepare($query);
$pdoExec = $pdoResult->execute(array(":login_at" => date("Y-m-d H:i:s"), ':audit_id' => $audit_id, ':login_by' => $user['id']));
$locked = 0; // Form is unlocked for the new user
} else {
// Timestamp is not older so the form is locked
$statement = $pdo->prepare("SELECT users.vorname, users.nachname, companies.company_name
FROM users
JOIN companies ON users.cid = companies.cid
WHERE users.id = :id");
$result = $statement->execute(array(':id' => $login['login_by']));
$locked_by = $statement->fetch();
$locked = 1; // Form is locked
}
}
?>
<?php if ($locked == 1) { ?>
<style>
div.fadeMe {
opacity: 0.1;
background: #000;
width: 100%;
height: 100%;
z-index: 100;
top: 0;
left: 0;
position: fixed;
}
</style>
<?php
// If the form is locked adding a transparent overlay to avoid changes on the form.
// Add a alert and inform the user about the situation.
?>
<div class="fadeMe"></div>
<div class="alert alert-danger mt-0 mb-0 rounded-0" role="alert">
<p class="mb-0 text-center">
<i class="fa-solid fa-lock mr-1"></i>
Die Bearbeitung dieses Fragebogens ist durch <?=$locked_by['vorname']?> <?=$locked_by['nachname']?> [<?=$locked_by['company_name']?>] gesperrt. </p>
</div>
<?php } else { ?>
<?php } ?>
</div>
My code in the AJAX file in "background":
Which is more or less the same as in the front end.
<?php
$audit_id = $_GET['audit_id'];
$user_id = $_GET['user_id'];
?>
<div id="login">
<?php
// Check if someone is logged in into that form
$statement = $pdo->prepare("SELECT login_at, login_by FROM audit WHERE id = :id");
$result = $statement->execute(array(':id' => $audit_id));
$login = $statement->fetch();
// Calculate the tim ebetween the now and the latest login timestamp
$ts2 = strtotime(date("Y-m-d H:i:s"));
$ts1 = strtotime($login['login_at']);
$seconds_diff = $ts2 - $ts1;
// If its the same user who locked the form latest do just an update of the timestamp
if ($login['login_by'] == $user_id) {
$query = "UPDATE audit
SET login_at = :login_at,
login_by = :login_by
WHERE id = :audit_id";
$pdoResult = $pdo->prepare($query);
$pdoExec = $pdoResult->execute(array(":login_at" => date("Y-m-d H:i:s"), ':audit_id' => $audit_id, ':login_by' => $user_id));
$locked = 0; // Form is not locked
} else {
// If its another user check if the timestamp is older then 10 seconds
if ($seconds_diff > 10) {
// The timestamp is older then 10 seconds. Update the SQL data for new user.
$query = "UPDATE audit
SET login_at = :login_at,
login_by = :login_by
WHERE id = :audit_id";
$pdoResult = $pdo->prepare($query);
$pdoExec = $pdoResult->execute(array(":login_at" => date("Y-m-d H:i:s"), ':audit_id' => $audit_id, ':login_by' => $user_id));
$locked = 0; // Form is unlocked for the new user
} else {
// Timestamp is not older so the form is locked
$statement = $pdo->prepare("SELECT users.vorname, users.nachname, companies.company_name
FROM users
JOIN companies ON users.cid = companies.cid
WHERE users.id = :id");
$result = $statement->execute(array(':id' => $login['login_by']));
$locked_by = $statement->fetch();
$locked = 1; // Form is locked
}
}
?>
<?php if ($locked == 1) { ?>
<style>
div.fadeMe {
opacity: 0.1;
background: #000;
width: 100%;
height: 100%;
z-index: 100;
top: 0;
left: 0;
position: fixed;
}
</style>
<?php
// If the form is locked adding a transparent overlay to avoid changes on the form.
// Add a alert and inform the user about the situation.
?>
<div class="fadeMe"></div>
<div class="alert alert-danger mt-0 mb-0 rounded-0" role="alert">
<p class="mb-0 text-center">
<i class="fa-solid fa-lock mr-1"></i>
<?php
// just for development purpose only to see the reaction time on the SQL update
// See every 3 seconds the updated time stamp and the calculated time difference in sseconds.
echo $login['login_at'];
echo " ";
echo $seconds_diff
?>
Die Bearbeitung dieses Fragebogens ist durch <?=$locked_by['vorname']?> <?=$locked_by['nachname']?> [<?=$locked_by['company_name']?>] gesperrt. </p>
</div>
<?php } else { ?>
<?php } ?>
</div>
Ok so there's a looooooot of issues here.
If you're gunna do any sort of ongoing validation, you don't return the entire HTML body every request, you return a small JSON reply and use that to control the HTML via JS. Generally it's a good practice to separate your HTML \ JS from your API \ validation layer altogether.
You shouldn't be managing data locks on the front end at all. Trusting the client to maintain data integrity is a big no-no in general. It seems like this should be handled as some sort of batched queue. You should never "recreate that effect" via locking and unlocking forms client side.
Your "silent" form key (or any validation stuff) should be handled via sessions or OAUTH, not GET params.
That said the issue is most likely a result of a race condition cause by table locking. If 2 users are both trying to lock \ access records which have a gap overlap user 2 has to wait until user 1's lock releases on that range.
This in turn makes the PHP "silently" block requests while they wait on the table locks to release. If you didn't properly index your user \ timestamp columns with the above queries, it could put a lock on all the other users update queries while it waits depending on how you set up your indexes... Which can then lead to your timer creating callback hell since every user is running it the whole time their logged in.
You should log your DB response time specifically to pin down if this is an issue, but regardless there's some architectural issues that should be addressed regardless.
I have a php code as shown below in which session timeout happen after 60 mins when there is no activity. The following code is inside the file /mno.php. My login and logout code is also in the same file /mno.php.
/mno.php
if (isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY'] > 3600)) {
session_destroy(); // destroy session data in storage
!isset($_SESSION['pageadmin']);
/* Update Table (START) */
$open="false";
$stmt= $connect->prepare("UPDATE trace_users SET open=? WHERE user_name=?");
$stmt->bind_param('ss', $open, $_SESSION['user_name']);
$stmt->execute();
/* Update Table (END) */
header('location: /mmo.php');
exit();
}
$_SESSION['LAST_ACTIVITY'] = time(); // update last activity time stamp
The table trace_users in the code keeps the track of all logged in users. In that table, there are two columns user_name and open. The value is set to true/false when any user log in/log out.
I have included sql query in which I am trying to update a table when there is no activity but unfortunately the column value is not getting set to false for that particular user when no activity happens for 60 mins.
This is what I have tried:
After doing some research, I think I have to run a timer (js/ajax). In the javascript shown below I have calculated the difference between the Last Activity and the Current time.
If its more than 60 mins, then it will update a db table. This is what I have tried but I believe more need to be done in order to update a table in db.
<script>
let x = setInterval(function() {
let lastActivity = <?php echo ($_SESSION['LAST_ACTIVITY']); ?>
let now = <?php echo time() ?>;
let difference = now - lastActivity;
if (difference > 3600) {
clearInterval(x);
}
}, 1000
);
</script>
Problem Statement:
I am wondering what changes I should make in the js (or php) code above so that when there is no activity for 60 mins, it should update the column open to false (in the table trace_users) for that particular user.
Edit 1:
My login code and session history code is in the same file /mno.php. I have placed everything in the same file /mno.php.
I think Vineys and jo0gbe4bstjbs answer is wrong because of when user close browser until 5 seconds, it can't update table after 60 mins and session too. Session deletes just after time in where set in php.ini configuration file.
And Do you mind requesting every 5 seconds is it good way to solve this? It is worst for performance.
If you want solve this problem with professionalism, you should add "last_request" column and delete "open" column from the table and after every request you should update last_requests value to current unix timestamp. And where getting users you should write:
$time = time() - 3600;
"SELECT * FROM `users` WHERE last_request > $time" //active users
"SELECT * FROM `users` WHERE last_request <= $time" //inactive users
And instead of ajax request every 5 seconds you should write setTimeout with 3600 second delay time which run window.location.href= '/mmo.php'; code.
Its way good if you want best performance and exactly result with 60 minute logout
I suppose you realize that this code
if (isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY'] > 3600)) {
//...
}
$_SESSION['LAST_ACTIVITY'] = time(); // update last activity time stamp
runs on every request and only when a request arrives
Imagine I visit your website and then go out shopping keeping the browser open. What do you think will happen?
NOTHING - because there will be no new request sent to you (assuming you haven't implemented any periodic ajax polling / Websocket mechanism)
So the server won't bother about me until I come back from shopping and refresh the page, only then would the server realize "Hmmm..This guy's LAST_ACTIVITY is older than an hour let me update my trace_users table and set open as false for him"
Coming to your proposed solution, it looks good and avoids the complications of websockets/periodic ajax requests
Just need some minor corrections, follow here for a basic demo
<script>
var lastActivity = <?php echo ($_SESSION['LAST_ACTIVITY']); ?>; //the timestamp of latest page refresh or navigation
//This will remain constant as long as page stays put
var now = <?php echo time() ?>; //This takes inital value (technically same as LAST_ACTIVITY) from server
// but later on it will be incremented by javascript to act as counter
var logoutAfter = 5; //I set 5 sec for demo purposes
var timer = setInterval(function() {
now++;
let delta = now - lastActivity;
if ( delta > logoutAfter) {
alert('you are logged out');
clearInterval(timer);
//DO AJAX REQUEST TO close.php
}
}, 1000);
</script>
Here the lastActivity will hold the timestamp when the page was sent by server to browser it will be never changed by scripts on the browser,
now is your counter that you will use to track how much time passed since page was loaded on the browser, you'll increment it every second and check if a given amount of time has been crossed
If true do a ajax request (or simply redirect to logout.php) where you would destroy session and update the trace_users table to mark the user as closed
UPDATE
So ajax will be like
$.ajax({
url: "/close.php",
type: 'POST', // GET also fine
data: { },
success: function(data) {
window.location.href= '/mmo.php';
},
error: function(jqXHR, textStatus, errorThrown) {
alert(textStatus);
}
});
and
close.php
<?php
session_start();
$logoutAfter = 5; //5 sec timeout for testing purposes
// I'm not sure whether the below if condition check is required here or not
// because we have already checked (whether to timeout or not ) in our javascript
// and we call close.php only when it's affirmative
// I encourage you to test and find out :)
if (isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY'] > $logoutAfter)) {
session_destroy(); // destroy session data in storage
!isset($_SESSION['pageadmin']);
/* Update Table (START) */
$open="false";
$stmt= $connect->prepare("UPDATE trace_users SET open=? WHERE user_name=?");
$stmt->bind_param('ss', $open, $_SESSION['user_name']);
$stmt->execute();
/* Update Table (END) */
//header('location: /mmo.php'); //<-- no need of it when url hit by ajax
exit();
}
else //<-- note the else
$_SESSION['LAST_ACTIVITY'] = time(); // update last activity time stamp
Page.php
<!-- CODE TO INCLUDE IN HEADER.PHP -->
<?php
session_start();
$_SESSION['LAST_ACTIVITY'] = time(); // update last activity time stamp
?>
<!-- CLOSE -->
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
</head>
<body>
</body>
<script>
let lastActivity = <?php echo ($_SESSION['LAST_ACTIVITY']); ?>; //the timestamp of latest page refresh or navigation
//This will remain constant as long as page stays put
let now = <?php echo time() ?>; //This takes inital value (technically same as LAST_ACTIVITY) from server+
// but later on it will be incremented by javascript to act as counter
let logoutAfter = 5; //I set 5 secs for demo purposes
let timer = setInterval(function() {
now++;
let delta = now - lastActivity;
if ( delta > logoutAfter) {
alert('you are logged out');
clearInterval(timer);
//DO AJAX REQUEST TO close.php
$.ajax({
url: "/mmo.php",
type: 'POST', // GET also fine
data: { },
success: function(data) {
},
error: function(jqXHR, textStatus, errorThrown) {
console.log("I am inside error");
alert(textStatus);
}
});
}
}, 1000); //<-- you can increse it( till <= logoutAfter ) for better performance as suggested by #"Space Coding"
</script>
</html>
mmo.php
<?php
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "myDB";
$connect = new mysqli($servername, $username, $password, $dbname);
if ($connect->connect_error) {
die("Connection failed: " . $connect->connect_error);
}
session_start();
$logoutAfter = 5; //5 sec timeout for testing purposes
if (isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY'] > $logoutAfter)) {
session_destroy(); // destroy session data in storage
!isset($_SESSION['pageadmin']);
/* Update Table (START) */
$open="false";
$stmt= $connect->prepare("UPDATE trace_users SET open=? WHERE user_name=?");
$usname = !empty($_SESSION['user_name'])?$_SESSION['user_name']:'';
$stmt->bind_param('ss', $open, $usname );
$stmt->execute();
/* Update Table (END) */
//header('location: /mmo.php'); //<-- no need of it when url hit by ajax
exit();
}
else //<-- note the else
$_SESSION['LAST_ACTIVITY'] = time(); // update last activity time stamp
?>
This is a simple time validation for web page:
$modified_on = isset($SERVER['HTTP_IF_MODIFIED_SINCE']) ? $SERVER['HTTP_IF_MODIFIED_SINCE'] : null;
$current_time = time();
if (!is_null($modified_on) && ($current_time - strtotime($modified_on)) > 3600) {
session_destroy();
...
}
header('Last-Modified: '.gmdate('D, d M Y H:i:s', $current_time).' GMT');
...
I am using PHP and MySQL in order to display live data on my webpage, refreshing every 1 second. All is currently working as expected although I would like to implement one new feature.
Currently on $( document ).ready() I start the live data feed by retrieving and displaying single rows of data from a transactions table. I can also start/stop the feed. Good so far.
I would now like to display the live data and have it start from the last 100 transactions. So for example, when a user opens the webpage they will initially see the past 100 transactions, then the live feed will start immediately afterwards (101, 102, 103, etc..).
Currently when the page is loaded the live feed starts at whatever transaction is returned by the sql query. Whereas I need it to start at that point minus 100
The past 100 transactions could -100 from the SerialNo as this is a unique, auto increment key in the database.
Everything is working regarding the live feed, including start/stop buttons. So I feel the issue is due to my query, especially the LIMIT 1 part. I have tried changing this to LIMIT 100 but when I do the webpage shows 100 records every 1 second.
I have two files, data.php and index.html. I have included the code for both below.
data.php
session_start();
include 'conn.php'; // database connection
header("Content-Type: text/event-stream");
header("Cache-Control: no-cache");
header("Access-Control-Allow-Origin: *");
$query = "SELECT TimeStamp, SerialNo FROM transactions ORDER BY TimeStamp DESC LIMIT 1";
$stmt = $conn->prepare($query);
$stmt->execute();
$result = $stmt->get_result();
while($row = $result->fetch_assoc()) {
//send request every x seconds
echo "retry: 1000\n\n";
echo "id: " .$row["SerialNo"]. "\n\n";
if ($_SESSION["lastSerialNo"] != $row["SerialNo"]) {
//store new "last" serial no in the session
$_SESSION["lastSerialNo"] = $row["SerialNo"];
//...send data to client
echo "data: ".$row['SerialNo']. ' ' .$row['TimeStamp']. "\n\n";
flush();
}
else {
// do nothing
}
}
index.html
<script type="text/javascript">
$("document").ready(function() {
// set the default stopped flag to false
var is_stopped = false;
var source = new EventSource("data.php");
var offline;
source.onmessage = function(event) {
if (is_stopped) {
// get data sent from data.php
offline = event.data;
// Put into storage
localStorage.setItem(event.lastEventId, offline);
// Retrieve from storage
offline = localStorage.getItem("offline");
}
if (!is_stopped) {
document.getElementById("result").innerHTML += "New transaction: " + event.data + "<br>";
}
};
$("document").ready(function() {
$("#start").click(function() {
// set stopped flag to false
is_stopped = false;
// loop through the localstorage
for (var i = 0; i < localStorage.length; i++) {
document.getElementById("result").innerHTML += "New transaction: " + localStorage.getItem(localStorage.key(i)) + " *<br>";
}
// clear local storage
localStorage.clear();
});
$("#stop").click(function() {
// set the stopped flag to true
is_stopped = true;
});
});
}); //end dom ready
</script>
<div id="result"><!--Server response here--></div>
<button id="stop"> stop</button>
<button id="start"> start</button>
Any help is appreciated.
I'm really new at back-end stuff and I'm building a Facebook app with multiple photo entries with voting mechanics. You can vote one or multiple entries once per day and it also detects your Facebook ID so that when you vote, the database detects your Facebook ID, the entry number you voted, and the date you voted. When you vote during the current date, a pop-up will appear that says "you successfully voted". Then when you try again the same date, the pop-up's message will change and instead, it will say "try to vote again tomorrow". It also shows the number of votes on the entry page.
My only problem is that when you're a first time user, it works fine, you can vote all the entries on the current date, but then when you come back the next day, when you vote, the pop-up will still say that you already voted, and the vote count will not update.
Here's the code for the PHP page: (edited this, already solved the problem, thanks for the help)
date_default_timezone_set('Asia/Manila');
// Get last vote date: fetch_date_voted returns none if user voted for first time
$current_date = date('Y-m-d');
$fetch_date_return = $this->fetch_date_voted($entry_id, $facebook_id, $table_prefix, $conn);
$last_vote_date = $fetch_date_return['last_date'];
$return['date_last_voted'] = $fetch_date_return;
// Below is a code i got from stackoverflow - 844641242329946 (kristina id)
/*if( $last_vote_date && ($last_vote_date == "none" || (strtotime($last_vote_date) + (60*60*24)) < strtotime($current_date))){*/
// Below is the original code
if( $last_vote_date == "none" || $last_vote_date < $current_date ) {
$table_name = $table_prefix . '_voter';
$query = $conn->query("
INSERT INTO $table_name
(facebook_id, entry_id, date_voted)
VALUES
($facebook_id, $entry_id, '$current_date')
");
//
// After doing INSERT, the variable $query will return a TRUE status
if ( $query ) {
// If the date fetched is TRUE, it will UPDATE
$update = $this->update_count($entry_id, $table_prefix, $conn);
// If update is successful, it will fetch the latest vote_count
if($update) {
$fetched_data = $this->fetch_current_count($entry_id, $table_prefix, $conn);
if ($fetched_data['status']) {
$return['status'] = true;
$return['vote_count'] = $fetched_data['vote_count'];
} else {
$return['status'] = false;
}
} else {
$return['status'] = false;
}
} else {
die('Error : ('. $conn->errno .') '. $conn->error);
$return['status'] = false;
$return['error_response'] = $conn->error;
}
} else {
$return['status'] = false;
$return['error_response'] = 'date_invalid';
}
echo json_encode($return);
//$query->close();
$conn->close();
}
$last_vote_date AND $current_date are string representations of a date, convert them to time and it works:
strotime($last_vote_date) < strotime($current_date)
Beware that this will always return true, because you want them to not use it for a day, so it would be:
if( $last_vote_date && ($last_vote_date == "none" || (strtotime($last_vote_date) + (60*60*24)) < strtotime($current_date))){
to add 24 hours.
I run a website for a youth sports program that features schedules, standings, and score reporting using simple PHP scripts that manipulate data stored in a MySQL database.
After a game is played, the winning coach will access the score reporting form for that particular game, enter the information, and click submit to update the schedule and standings accordingly. They are then automatically redirected to the schedule page that they came from.
However, several times a season, a coach will unintentionally duplicate a score submission (sometimes creating as many as three or four instances) which does not affect the result posted on the schedule, but does throw the data in the standings out of whack. I'm not sure how exactly this is being accomplished, but I'm trying to fix the problem.
I've been reading up as much as possible on here and the web and believe that I need to implement some sort of token system to the reporting script, but I'm unsure how to exactly write the code? Any advice here would be GREATLY appreciated. Here is the script itself:
<?php
// Connect to the database:
require ('../mysqli_connect.php');
// Validate the school:
if (empty($_POST['school'])) {
echo "You forgot to enter your school.<br>";
$validate = 'false';
} elseif ($_POST['school'] != $_POST['away_team'] && $_POST['school'] != $_POST['home_team']) {
echo "Your school does not match one of the two on file for this game.<br>";
$validate = 'false';
} else {
$school = mysqli_real_escape_string($db, trim($_POST['school']));
$validate = 'true';
}
// Validate the password:
if (empty($_POST['pass'])) {
echo "You forgot to enter your password.<br>";
$validate = 'false';
} else {
$pass = mysqli_real_escape_string($db, trim($_POST['pass']));
$validate = 'true';
}
// Validate the away score:
if (!isset($_POST['away_score'])) {
echo "You forgot to enter the away score.<br>";
$validate = 'false';
} elseif (!is_numeric($_POST['away_score'])) {
echo "You entered an invalid score for the away team.<br>";
$validate = 'false';
} else {
$away_score_confirm = mysqli_real_escape_string($db, trim($_POST['away_score']));
$validate = 'true';
}
// Validate the home score:
if (!isset($_POST['away_score'])) {
echo "You forgot to enter the home score.<br>";
$validate = 'false';
} elseif (!is_numeric($_POST['$home_score']) && $_POST['$home_score'] < 0 ) {
echo "You entered an invalid score for the home team.<br>";
$validate = 'false';
} else {
$home_score_confirm = mysqli_real_escape_string($db, trim($_POST['home_score']));
$validate = 'true';
}
// Determine the winner and loser, and set variables:
if ($_POST['away_score'] > $_POST['home_score']) {
$winner = mysqli_real_escape_string($db, trim($_POST['away_team']));
$winner_score = mysqli_real_escape_string($db, trim($_POST['away_score']));
$loser = mysqli_real_escape_string($db, trim($_POST['home_team']));
$loser_score = mysqli_real_escape_string($db, trim($_POST['home_score']));
$tie = 'no';
} else if ($_POST['away_score'] < $_POST['home_score']) {
$winner = mysqli_real_escape_string($db, trim($_POST['home_team']));
$winner_score = mysqli_real_escape_string($db, trim($_POST['home_score']));
$loser = mysqli_real_escape_string($db, trim($_POST['away_team']));
$loser_score = mysqli_real_escape_string($db, trim($_POST['away_score']));
$tie = 'no';
} else if ($_POST['away_score'] == $_POST['home_score']) {
$tie = 'yes';
$tie1 = mysqli_real_escape_string($db, trim($_POST['away_team']));
$tie2 = mysqli_real_escape_string($db, trim($_POST['home_team']));
$tie_score = mysqli_real_escape_string($db, trim($_POST['away_score']));
}
// Declare remaining hidden inputs as variables:
$league = $_POST['league'];
$table = mysqli_real_escape_string($db, $_POST['table']);
$game_id = mysqli_real_escape_string($db, $_POST['game_id']);
$sport = $_POST['sport'];
// Declare remaining hidden inputs as variables:
$standings_league = $table . "_standings";
// If all conditions are met, process the form:
if ($validate != 'false') {
$q1 = "SELECT school_id FROM user_schools WHERE (school_name='$school' AND pass='$pass')";
$r1 = mysqli_query($db, $q1);
$num = mysqli_num_rows($r1);
if ($num == 1) {
// Get the game ID:
$q2 = "SELECT $game_id FROM $table";
$r2 = mysqli_query($db, $q2);
// Get the row for the game ID:
$row = mysqli_fetch_array($r2, MYSQLI_NUM);
// Perform an UPDATE query to modify the game scores:
$q3 = "UPDATE $table SET home_score='$home_score_confirm', away_score='$away_score_confirm' WHERE game_id=$row[0]";
$r3 = mysqli_query($db, $q3);
if (mysqli_affected_rows($db) == 1) {
$confirm = 'true';
} else {
$confirm = 'false';
}
// Update the winning team in the standings:
$q4 = "SELECT school_id FROM $standings_league WHERE school_name='$winner'";
$r4 = mysqli_query($db, $q4);
// Get the row for the school:
$row2 = mysqli_fetch_array($r4, MYSQLI_NUM);
$q5 = "UPDATE $standings_league SET games=games + 1, win=win + 1, pts_for=pts_for + '$winner_score', pts_against=pts_against + '$loser_score' WHERE school_id=$row2[0]";
$r5 = mysqli_query($db, $q5);
$q6 = "UPDATE $standings_league SET pct=(win / games), avg_for=(pts_for / games), avg_against=(pts_against / games) WHERE school_id=$row2[0]";
$r6 = mysqli_query($db, $q6);
// Update the losing team in the standings:
$q7 = "SELECT school_id FROM $standings_league WHERE school_name='$loser'";
$r7 = mysqli_query($db, $q7);
// Get the row for the school:
$row3 = mysqli_fetch_array($r7, MYSQLI_NUM);
$q8 = "UPDATE $standings_league SET games=games + 1, loss=loss+1, pts_for=pts_for + '$loser_score', pts_against=pts_against + '$winner_score' WHERE school_id=$row3[0]";
$r8 = mysqli_query($db, $q8);
$q9 = "UPDATE $standings_league SET pct=(win / games), avg_for=(pts_for / games), avg_against=(pts_against / games) WHERE school_id=$row3[0]";
$r9 = mysqli_query($db, $q9);
if ($confirm != 'false') {
header('Location: schedules_' . $sport . '_' . $league . '.html?league=' . $league .'&table=' . $table);
} else {
echo "The scores could not be reported due to a system error. Apologies for the inconvenience. If this problem continues, please contact us directly.";
}
} else {
echo "Your school and password combination do not match those on file for this game.";
}
}
mysqli_close($db);
?>
My guess is that these coaches are simply clicking the submit button multiple times while the form is waiting for a response from the server. You could use JS to disable (or hide) the button after the first click:
var button = document.querySelector('input[type=submit]'); // Use whatever selector is appropriate here
button.addEventListener('click', function(ev) {
if (!button.classList.contains('submitting')) { // If this is our first click...
button.className += ' submitting';
} else { // Otherwise prevent submission
ev.preventDefault();
}
});
If you have jQuery available to you, you could also just handle the entire submission process via JS and block it there.
You should be aware of presenting some sort of feedback onto the screen to let the user know that a submission is currently in progress, that'll help alleviate some button mashing as well.
One solution is to add a unique value to the form and when its submitted, add the value to a session. If they hit submit button more than once ( probably what is happening ), it will accept only one submition
Example:
<form>
<input type="hidden" name="submit_id" value="<?php echo mt_rand(); ?>">
// rest of the form
</form>
Php file recieving:
<?php
session_start();
if ( isset( $_POST['submit_id'] ) ) {
if ( !isset( $_SESSION['submit_id'] ) ) {
$_SESSION['submit_id'] = array();
}
if ( !in_array( $_POST['submit_id'], $_SESSION['submit_id'] ) ) {
// validate posted values
// when data is valid, register form as submitted
$_SESSION['submit_id'][] = $_POST['submit_id'];
// add the submitted form data to database
}
else {
echo 'Your data has already been submitted';
}
}
I don't want to read your code so I'll suggest a strategy.
I agree with #relic. Your coach is probably double-clicking the button.
If you can assume that different users will never submit two forms in the same second, then you can "filter" your table to accept only one entry for any given second. Make an index for the (new) seconds column, and make it unique. This will prevent insertions of rows to that table if an entry already exits for that second.
If this leads to conflicts, you can introduce restrictions that enforce every entry to be unique for a combination of other fields in the table. This is called compound keys (SQL). You formulate something like, for this game and user, there can only be one score registration.
MySQL:
create table scores (game_id int, user_id int, score int );
alter table scores add unique index uniq_gus (game_id, user_id, score);
insert into scores (game_id, user_id, score) values (1, 1, 10);
insert into scores (game_id, user_id, score) values (1, 1, 10);
ERROR 1062 (23000): Duplicate entry '1-1-10' for key 'uniq_gus'
In addition, you may want to prevent double-submissions (assuming jQuery):
(function($){
var btn = $('button[type="submit"]');
btn.click(function(event){
event.preventDefault();
btn.attr('disabled','disabled');
$.ajax({
url: 'http://foo.bar/form-endpoint.php',
success: function (data, status, xhr) {
btn.removeAttr('disabled');
},
})
})
})(jQuery);