I have a text based game site (Mafia game) written in old php/mysql style. I have no to very less knowledge of PHP/MYSQL i am learning it though. So i am having problems with one of file which reloads every 5 second via ajax , it contains few Mysql query which checks messages, forum messages,transfer,attacks etc and depending on the check it shows alert to users if they get any new message,forum messages,transfer,attacks etc. My site is using VPS right now and if i set the refresh rate to 5 seconds it overlaods the VPS within few minutes so i have to set the refresh time to 20 seconds or more. I would like to know if there is any problems with query or any suggestion to optimize query/php code. Below is code of my file ajax.php which needs to be reloaded every 5 seconds
<?php
include("funcs.php");
global $tab, $time, $id, $tru, $old;
$round=$_GET['tru'];
$tO=0;
$moFo='r'.$round.'_mafiosi';
$brd=$tab['board'];
$query="select msg,atk,ivt,transf from $moFo where id='$id'";
$result=mysql_query($query);
$ans=mysql_fetch_assoc($result);
foreach($ans as $key=>$value)
{
$tO+=$value;
}
$rtn='#'.$mafioMsg;
echo "$tO$rtn";
?>
#
and below is the jquery/javascript i am using :
<script type="text/javascript" >
var onOff=false;
var replyText='';
window.onload=mainF;
function hideRedNotif()
{
document.getElementById('redNotif').style.display='none';
}
function mainF()
{
fetchNotif();
Updtr=window.setInterval(fetchNotif,25000);
}
function toggleNotif()
{
document.getElementById('redNotif').style.display='none';
if(onOff==false)
{
document.getElementById('parentReply').style.display='';
onOff=true;
}
else
{
document.getElementById('parentReply').style.display='none';
onOff=false;
}
}
function getAjxObject()
{
try {
var o=new XMLHttpRequest();
}
catch(exception)
{
var o=new ActiveXObject('Microsoft.XMLHTTP');
}
return o;
}
function fetchNotif()
{
roundN=document.getElementById('roundName').value;
var o=getAjxObject();
o.open('GET','notifAjx.php?openSes=in&&tru='+roundN,true);
o.onreadystatechange=execute;
o.send();
function execute()
{
if(o.readyState==4 && o.status==200)
{
var countF=0;
resp=o.responseText;
rsp=resp.split('#');
dom=document.getElementById('notifM');
dom.innerHTML=rsp[0];
//document.getElementById('chatRoller').innerHTML=rsp[1];
//if(rsp[1]!=replyText )
//{
//document.getElementById('redNotif').style.display='';
//replyText=rsp[1];
//}
}
}
}
function sendReply()
{
var o2=getAjxObject();
roundN=document.getElementById('roundName').value;
m=document.getElementById('replyText').value;
msg='&&reply=1&&msg='+m;
url='notifAjx.php?tru='+roundN+msg;
o2.open('GET',url,true);
document.getElementById('replyText').value='';
o2.onreadystatechange=execute;
o2.send();
function execute()
{
if(o2.readyState==4 && o2.status==200)
{
}
}
}
</script>
UPDATE- Thanks to everyone for checking my issue, I took screenshots of my DB tables please check if it helps or let me know what else should i provide.
http://i.imgur.com/VJSU2.jpg
http://i.imgur.com/5O6T0.jpg
I will appreciate any suggestion/help.
Thanks & Regards
Prashant
please check for indexing in the table '$moFo'
and check whats the volume of the data you are dealing with, if its high then do archive them or use sharding.
I expect you may have issues because if your asynchronous request takes more than 5 seconds, you'll start to get a backlog. It might sound counter-intuitive, but I recommend making your asynchronous requests a bit more synchronous:
Currently you're using setInterval to run your check every five seconds, regardless of whether a response has come back. What you could do instead is use setTimeout to get it started and then set another timeout when your response has come back, whether it was successful or not. This way, your responses will never start to overlap.
In practice:
Change your mainF() function to be
function mainF()
{
fetchNotif();
Updtr=window.setTimeout(fetchNotif,25000);
}
Then change your fetchNotif() execute() function to set another timeout once it's processed
Updtr=window.setTimeout(fetchNotif,25000);
You may want to wrap that one in an if to check for readyState == 4 but don't check for status == 200 because you probably want it to try again even if the previous attempt failed.
Related
A POS software overwrites the orders in a text fie. I am trying to make a Kitchen Display which shows the orders.
My php script reads from that text file...
A comparision is made after every 1 second using sleep(1); to check if a new order has arrived.
<?php
$f1 = fopen("G:/order.txt", 'r');
$firstLine1 = fgets($f1);
fclose($f1);
sleep(1);
$f2 = fopen("G:/order.txt", 'r');
$firstLine2 = fgets($f2);
fclose($f2);
if($firstLine1 != $firstLine2) {
$fh = fopen("G:/order.txt", "r");
echo "<div>";
while ($line = fgets($fh)) {
echo ($line);
}
fclose($fh);
echo "</div>";
}
?>
And using Ajax I run that script every 1 mini second.
<script>
function loadDoc(){
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
$("p").before(this.responseText);
}
};
xhttp.open("GET", "order.php", true);
xhttp.send();
}
window.setInterval(function(){
loadDoc()
}, 1);
</script>
The problem is that that around 50 Divs are created for every new order where it should be just 1.
1 Div per order.
Please help me I'm messed up.
I think this will work better. Since you're making repeated ajax calls to run the same script, it doesn't make much sense to read repeatedly from the file during each run. Plus your comparison doesn't make any reference to what happened last time the script ran, which, combined with the insane frequency of ajax requests, is resulting in endless duplicate results.
Instead, compare the order ID retrieved on each run to the one retrieved on the previous run. Also, you need to increase the interval between requests, otherwise you'll swamp your server, and also run the risk of concurrency problems where your next request tries to begin before the previous one finishes (don't forget that ajax calls run asynchronously).
PHP
<?php
session_start(); //enable sessions
$f1 = fopen("G:/order.txt", 'r');
$firstLine = fgets($f1);
//check whether a previous order ID has been stored during this session.
if (isset($_SESSION["lastOrderID"])) {
//if the order ID in the file is the same as the last stored one in the session, don't send any data to the client
if ($firstLine == $_SESSION["lastOrderID"])
{
echo "";
fclose($f1);
die();
}
}
echo "<div>";
echo $firstLine;
while ($line = fgets($f1)) {
echo ($line);
}
echo "</div>";
//store the last order ID in the session
$_SESSION["lastOrderID"] = $firstLine;
fclose($f1);
JavaScript
<script>
function loadDoc(){
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
$("p").before(this.responseText);
}
};
xhttp.open("GET", "order.php", true);
xhttp.send();
}
window.setInterval(loadDoc, 10000); //refresh every 10 seconds. You can decrease the interval if you like, but don't make it so short that it regularly starts another request before the previous one has completed. You can use your browser's network tools to see how the long requests normally take, and use that to help you decide on a suitable value. Leave some headroom for the occasional slowdown.
</script>
Bear in mind that this will only work for the duration of the session - i.e. normally just for as long as the browser window is open, or until the session times out. You can google how to increase the session timeout if necessary. If you require anything more persistent than this (i.e. to remember the last Order ID between sessions) then you should use another text file, or a database in order to record this information, instead of the session.
I'd also like to re-iterate here my concern that your POS software seems overly simplistic, at least based on the details given in the question, and that for audit and other fairly obvious purposes, it might make sense to persist historical records of all orders using a database, instead of over-writing a text file each time a new order is entered.
I'm having a problem with an ajax call.
I have some code set up to run a function every 2 seconds which looks to see if the content has been updated or not with WordPress ajax, does some work with php, then updates a database:
window.setInterval( "updateContent()", 2000 );
function updateContent(){
if($('#needcontent').hasClass('yes')){
CONTENT.updateContent( 'monitor' , ids );
}
}
$(function() {
CONTENT= {
updateContent: function(callback, data){
data = {
action: 'myplugin_do_ajax',
callback: callback,
data: data
};
$.post(ajaxurl, data, function(response){
switch(data.callback){
case 'monitor' :
data_returned = eval("(" + response + ")");
if(data_returned.completed == 'true'){
//Adjust the DOM because there was a content update, and remove the class "yes" from #needcontent to stop the check until next time
}
else{
//Do nothing because no content was found, let the Interval run again
}
break;
}
}
}
}
The problem I'm finding is that sometimes the content is quite large, and ends up locking the table while php updates the database. The ajax call runs once, runs into a database lock, and doens't return anything until the database is unlocked again. The database could be locked for a 10 second period, resulting in 1 run and 4 not-run calls.
UPDATE:
It's not the database locking, it's the php function taking longer than 2 seconds to return, causing the Interval to loop again and again without a response.
What's happening is those 4 not-run ajax calls then begin to fire one right after the other like they are trying to catch up or something.
I've tried increasing the Interval time to 10 seconds, but that doesn't solve the problem because if the database is locked for 11 seconds it'll still fire twice.
I've tried using global variables in Javascript (yuck) to stop the Interval from calling the function, but that doesn't seem to work either.
UPDATE 2:
I answered my own question below to what worked for me.
try this:
window.updateCheck= window.setInterval( "updateContent()", 2000 );
function updateContent(){
if($('#needcontent').hasClass('yes')){
CONTENT.updateContent( 'monitor' , ids );
clearInterval(window.updateCheck);
}
}
$(function() {
CONTENT= {
updateContent: function(callback, data){
data = {
action: 'myplugin_do_ajax',
callback: callback,
data: data
};
if(window.ajaxCall) window.ajaxCall.abort();
window.ajaxCall= $.post(ajaxurl, data, function(response){
window.updateCheck= window.setInterval( "updateContent()", 2000 );
switch(data.callback){
case 'monitor' :
data_returned = eval("(" + response + ")");
if(data_returned.completed == 'true'){
//Adjust the DOM because there was a content update, and remove the class "yes" from #needcontent to stop the check until next time
}
else{
//Do nothing because no content was found, let the Interval run again
}
break;
}
}
}
}
what we did here was to put the interval in a global variable, and also the ajax call ($.post() call actually), then when the conditions of updating is checked, we stop the interval, kill all the other active or queued request and send the ajax request to the server.
while the request is being sent to the server the update checks are stopped, then as soon as the server responds to the request we start the update check again!
charlietfl's comment on my OP got me thinking about the difference between setInterval and setTimeout, and I realized that:
a) setInterval would continuously run, regardless if a result is returned or not. In my case, using ajax, the function was being call asynchronously so the setInterval wouldn't care if a result was returned.
b) If I changed the code to use setTimeout, I could control the outcome more.
This is what I did.
Firstly, remove the setInterval function completely, it's not needed.
Then I changed my switch case to this:
case 'monitor' :
var monitor = false;
data_returned = eval("(" + response + ")");
if(data_returned.completed == 'true'){
//Adjust the DOM because there was a content update, and remove the class "yes" from #needcontent to stop the check until next time
}
else{
//Run the monitor after a 2 second timeout.
var ids = j('.contentDiv').attr('id');
window.setTimeout(CONTENT.updateContent( 'monitor' , ids ) , 2000);
}
break;
I've created a working damage per second loop although it has a few bugs that need to be worked out.
i'd like the 'target has been destroyed' message to be displayed instantly, not 1.2 seconds after the current hitpoints reach 0.
the major bug is that if you click the attack button multiple times, it will initiate the setInterval multiple times and the damage will be inflicted every 1.2 seconds for every time you clicked it, so it can execute multiple times.
The initial attack should happen instantly.
Any thoughts or ideas? I have tried the using a do while loop but i couldn't get that code to work at all. I've only had success with the setInterval function.
I have a working script on my website and i'll post the code here as well.
$(document).ready(function(){
var dmg = 60;
var curr_hp = 1200;
var tot_hp = 1200;
$('#attk_spd').html('1.2 seconds');
$('#dmg').html('60'); $('#curr_hp').html('1200');
$('#tot_hp').html('1200');
$("#btn").click(function(){
$('#attk').html('You are currently attacking your target.');
setInterval(
function () {
if (curr_hp > 0) {
curr_hp = curr_hp - dmg;
$('#curr_hp').html(curr_hp);
} else { $('#attk').html('Your target has been destroyed.');
}
},
1200);
})
});
And here's the current working version in action:
http://www.evenstar-online.com/Jquery_snippets/dpsloop.php
Use setTimeout instead of setInterval, so you can control precisely whether to attack again. Then you can just call the function once and the first attack happens immediately. This is a little weird to explain; follow the code below :)
Also:
Taking care to indent your code correctly makes it much easier to follow at a glance :)
Don't use $.html unless you're actually assigning HTML! Get in the habit of using $.text instead, or you'll end up trying to stick an angle bracket somewhere and have no idea why all the text disappeared.
I ended up with:
$(document).ready(function(){
var dmg = 60;
var curr_hp = 1200;
var tot_hp = 1200;
$('#attk_spd').text('1.2 seconds');
$('#dmg').text('60');
$('#curr_hp').text('1200');
$('#tot_hp').text('1200');
var attack_timer;
$("#btn").click(function() {
if (attack_timer) {
// We're already waiting for the next attack, so do nothing
return;
}
$('#attk').text('You are currently attacking your target.');
var attack_once = function() {
// Always attack immediately
curr_hp -= dmg;
$('#curr_hp').text(curr_hp);
// Only schedule another attack if the target is still alive
if (curr_hp > 0) {
attack_timer = setTimeout(attack_once, 1200);
}
else {
$('#attk').text('Your target has been destroyed.');
}
};
attack_once();
})
});
First sorry for my bad english, i'm a new user but i read long ago this site and help me many problem resolve. Thanks all for this. Now unfortunately i dont find resolve for my problem.
I dont know why 2000 ms my all ajax call. All at same what thing the called .php file.
I try a lot of technique to resolve this but not help.
The task is refresh many div content in "real time" with database syncronization.
The site contains some timer. When the timer text equal 00:00:00 i call the update script.
my ajax call:
$(function() {
function update()
{
$.ajax({
type: "GET",
url: "ajax/update.php",
async: true,
success: function() {
update();
}
});
}
update();
});
my update php:
include 'inc/config.php';
include 'inc/conn/connopn.php';
$sDataForSync = "";
$iRowsNum = 0;
$sGetDataQuery = mysql_query("select `AID`, `PN` FROM `my_table1`;");
if (mysql_num_rows($sGetDataQuery ) > 0) {
while ($row = mysql_fetch_array($sGetDataQuery )) {
$iRowsNum++;
if ($iRowsNum == mysql_num_rows($sGetDataQuery )) {
$sDataForSync .= $row['AID'] . "|" . $row['PN'];
} else {
$sDataForSync .= $row['AID'] . "|" . $row['PN'] . PHP_EOL;
}
}
}
file_put_contents("updates.txt",$sDataForSync );
/* for now only write to text file, but later i would like to update in database */
include 'inc/conn/conncls.php';
The table contains max 30-40 rows and i using indexes, but still 2 seconds the response.
I need 200-400 ms, max 500ms responsetime with prospective mysql update query.
firefox results
Please help me decreases the time.
Thanks for all!
SOLVED. 1 sec is my fail. I left the second parameter from mysql_query. mysql_query("select",$dbconn); The another second is my web server fail. Too slowly. The mysql_connect(); is 1 second in localhost but on the remote server the full operation is 50-80 ms. Thanks for all the posts.
A site I'm working on takes table data, counts that table data and uses a standard loop to display it. Here's some of the code:
<?php
$output='';
$count=count($deal_datas);
$face_value="";
$deal_price="";
//var_dump(400*20/100);
$save_value='';
$save_value_present='';
$category_name='';
$cat_ids=array();
$deal_link='';
$address_array=array();
$address='';
$website_name='';
$website_data=array();
if($count!=0) {
for($i=0;$i<$count;$i++) {
$website_data=get_single_row("web_sites",array("id"=>$deal_datas[$i]->site_id));
if(count($website_data)!=0) {
$website_name=$website_data[0]->name;
}
$address_array=array();
$cat_ids=explode(",",$deal_datas[$i]->sub_category_ids);
if(count($cat_ids)!=0) {
$where_class=array("id"=>$cat_ids[0]);
$category_names=get_single_row("sub_category",$where_class);
if(count($category_names)!=0) {
$category_name=$category_names[0]->name;
} else {
$category_name="All";
}
} else {
$category_name="All";
}
$face_value=str_replace("USD","",$deal_datas[$i]->deal_face_value);
$face_value=str_replace("$","",$face_value);
$face_value=(int)str_replace(",","",$face_value);
$save_value_present=(int)str_replace("%","",$deal_datas[$i]->deal_save_percent);
if($deal_datas[$i]->deal_price!="") {
$deal_price=str_replace("USD","",$deal_datas[$i]->deal_price);
$deal_price=(int)str_replace("$","",$deal_price);
$save_value=$deal_price;
} else {
$save_value=$face_value*$save_value_present/100;
}
$time_zone_utc=$deal_datas[$i]->deal_oe_end_date;
$end_date=$time_zone_utc;
if($website_name!="kgbdeals") {
$deal_link=base_url()."deals/iframe/".$deal_datas[$i]->slug;
} else {
$deal_link=$deal_datas[$i]->deal_link;
}
if($deal_datas[$i]->deal_address==0 or $deal_datas[$i]->deal_zip_code==0) {
$deal_datas[$i]->deal_address="";
$deal_datas[$i]->deal_zip_code="";
}
if($deal_datas[$i]->deal_zip_code!="") {
$address_array[]=$deal_datas[$i]->deal_zip_code;
}
if($deal_datas[$i]->deal_address!="") {
$address_array[]=$deal_datas[$i]->deal_address;
}
$address=implode(" ",$address_array);
if($deal_datas[$i]->deal_city!="") {
if(empty($address_array)) {
$address.=$deal_datas[$i]->deal_city;
} else {
$address.=" - ".$deal_datas[$i]->deal_city;
}
//Check for valid image
$deal_image=base_url().'uploads/deals/'.$deal_datas[$i]->slug.'.jpg';
if(getimagesize($deal_image)) {
$valid_image=1;
} else {
$valid_image=0;
}
if($i%2==0) {
$output.='<div class="clsDeal_Whole_Cont clearfix">
Then it outputs the tabled list of data, etc.
Problem is, sometimes that data is sometimes 120 entries that are placed on the screen and the load takes ages.
What I want to do display the data 4 or 8 entries at a time. Then, as the user scrolls, add more in.
Alternatively - to load 4. Display them. Then load 4 more, display them. And so on, so that way the user actually gets to view the contents rather than waiting for the whole list (if this is simpler). Is that possible?
I'm not using jquery for this, though I know I would need to for the whole scroll down bit. So, would there be a way to rewrite the above php in order to display chunks of 4 until the final result is reached?
You have several problems here, beginning with how you ask the question. Be sure to include all the relevant code. You have a truncated code listing that doesn't deal with the problem at hand; how to break up a long set of data into a human readable format. You do not describe how you're getting your initial data $deals_data. The implementation details of how your format your output is not relevant to this question. Further, your code is a bit of the mess and doesn't follow the Single Responsibility Principle.
You should put your data selection and display functionality into single functions:
//returns n through z rows of data. If '0' is provided for finish, returns all rows
function getData($start=0, $finish=0 {
$data = array();
if ($finish == 0) {
//get all data
} else {
//get limited amount of data
}
return $data;
}
//returns first $limit rows of data as an html-encoded output string
function displayDeals($deal_data, $limit) {
...
}
That function should call a separate function for each of your rows:
//Returns a string of html-encoded data for one row
function displayRow($row_data) {
...
}
This displayRow function will be called $limit number of times by displayDeals. Once you get that working, it becomes much simpler to use AJAX for infinite scrolling. You simply create a php function:
function getMoreRows($start, $numberOfRows) {
$data = getData($start, $start+$numberOfRows);
$output = displayDeals($data, $numberOfRows);
return $ouput;
}
This will return that output to the AJAX function that called the php code. Because it's encoded as HTML you simply replace whatever available div with that new string.
Note that JQuery will make this AJAX easy, but you will need some javascript in order to make this functional, or suffer a long round-trip call to a new php page each time. The latter is easy, but avoids making the user interface smooth and lazy-loaded like you want. Here is how:
$.ajax({ url: '/my/site',
data: {action: 'getMoreData'},
type: 'post',
success: function(output) {
//replace your div with new data
}
});
On the server side you need a php page to handle the request:
if(isset($_POST['action']) && !empty($_POST['action'])) {
$action = $_POST['action'];
switch($action) {
case 'getMoreData' : getMoreRows($_POST['lastDataIndex'], $_POST['numberOfRowsToFetch']);break;
// ...etc...
}
}
As a minor post-script about style: you should be cautious about mixing if and if-else styles, in regards to brackets. Generally, you want you code to be tight and quickly readable, and you want to never be in doubt if code is in a block. Personally, I always use brackets with if and if-else, but you should avoid using brackets in your if statement and not in your else case at the very least. Keep an eye on human readability, or you will find that you'll be frustrated by random bugs that arise because you assume a thing is or is not in a block when it's the opposite case.
It seems to me that, ostensibly, you want to paginate the data. That's easy to do. Just have next and previous buttons on your page which are dynamically generated to link to offsets in your list (i.e. page?offset = 4, page?offset = 8). Then just load four items (offset+1, offset+2, offset+3, and offset+4) on each page.