Overcoming 'max_user_connections' issue with polling/comet/websockets - javascript

I have a php/mysql auction site which uses a while/break loop to check on the current active item in a items table using ajax polling. It breaks if there is a new bid or a new lot. The server script is:
if ($action == "ping"){
$idle_lot = $_POST['lot'];
$idle_bid = $_POST['bid'];
$timeout = 15;
$now = time();
while((time() - $now) < $timeout) {
$get_bid_status = $db->prepare("SELECT current_bid, lot_number FROM ".$lots_table." WHERE lot_status='active' LIMIT 1");
$get_bid_status->execute(array());
$existCount = $get_bid_status->rowCount();
if ($existCount > 0 ) {
while($row = $get_bid_status->fetch()) {
$current_bid = $row["current_bid"];
$lot_number = $row["lot_number"];
}
if (($current_bid != $idle_bid)||($idle_lot != $lot_number)) break;
sleep(1);
} else {
$return_array[99] = "closed";
}
if ($existCount == 0 ) break;
}
//other php code here
}
The client side is a simple AJAX function:
function waitForMsg(lot, bid){
$.ajax({
type: "POST",
url: "live_bidding_script.php",
data: { action: "ping", lot: lot, bid: bid},
dataType: "json",
async: true,
cache: false,
timeout:50000,
success: function(data){
//other jquery code here
setTimeout(function(){waitForMsg(lot, bid)}, 1000);
}
},
error: function(XMLHttpRequest, textStatus, errorThrown){
//other jquery code here
setTimeout(function(){waitForMsg(lot, bid)}, 1000);
}
});};
The script was working very well in testing, but when we had a simulated auction, we suddenly crashed and burned. We got the dreaded:
SQLSTATE[42000] [1226] User 'XXXX' has exceeded the 'max_user_connections' resource (current value: 20)
I removed the loop, which seemed to be the major cause of the problem, (ie kept the connection open for 15secs at a time, and quickly used up all the 20 connections) and reverted back to simple polling.
Now from reading dozens of articles, polling and even long polling is not the 'way to go' so to speak. So I am about to recode the site.
My question is out of the newest technologies which use websockets (ie: pub nub, node.js, socket.io or even Comet) would they get around this issue of 'max_server_connections', and if so please explain how/why.
I understand the newer technologies work differently but they all seem to have a fallback approach (usually polling) if WS protocols are not available, which leads me to believe if we had 1000 concurrent users and 20+ had older browsers for example, we would still get the same 'max_server_connections' issue.
PS: we are on a prepaid hosted server for the next few years and simply increasing the number of 'max_user_connections' is a no go. Changing hosts may be an option, albeit a very expensive/time consuming exercise.
Thanks.

Related

How can I send data to MySQL server on JavaScript if statement

I'm trying to make a snake game within my website, and have been running into the issue of not being able to send score and user data (for a leaderboard) to my SQL database. I'm really new to web dev, so I'm not sure if maybe there's a super simple fix I just keep overlooking. Here's the part of the game's JavaScript code block that I am focusing on:
// snake occupies same space as a body part. reset game
if (cell.x === snake.cells[i].x && cell.y === snake.cells[i].y) {
//Ask for new user if one isn't registered
if (document.getElementById("userV").innerHTML == "User: ____")
{
document.getElementById("userData").innerHTML = window. prompt("User:");
document.getElementById("userVisible").innerHTML = "User: " +
document.getElementById("userData").innerHTML;
}
/*
*Here is where I need to send user and score data to snake_scores table
*/
snake.x = 160;
snake.y = 160;
snake.cells = [];
snake.maxCells = 4;
snake.dx = grid;
snake.dy = 0;
snake.score = 0;
document.getElementById("scoreData").innerHTML = snake.score;
document.getElementById("scoreVisible").innerHTML = "Score: " + snake.score;
apple.x = getRandomInt(0, 25) * grid;
apple.y = getRandomInt(0, 25) * grid;
}
So overall, my issue is that I can't figure out how to send these JS values through PHP and to my SQL server.
I'll make some assumptions about the game page itself, given that you probably don't want the page to refresh during play a good solution would be Ajax (Asynchronous JavaScript And XML). Essentially this is making a post request in the background to your server without reloading the page.
I find jQuery pretty easy to use:
https://api.jquery.com/jQuery.post/
$.ajax({
type: "POST",
url: url,
data: data,
success: success,
dataType: dataType
});
So using Ajax to post to a url that is expecting the information to then update server side you would access this in php using something similar to the following.
$leaderboard = $_POST['leaderboard']
Hope this points you in the right direction at least. Good luck on the game.

Notification on background PHP

I have a web application that use notification to inform user about anything new (just like Facebook).
My solution is that I send a request every three seconds to check the database if there is anything new to display (jQuery and AJAX). However, this makes the application slow, since a request is sent to check tables every three seconds.
I want to know how to make these notifications work without interrupting the application.
So this is my JS code:
jQuery(document).ready(function(){
LoopNotificationCRM();
});
function LoopNotificationCRM(){
setTimeout('LoopNotificationCRM();',3000);
$.ajax({
async: false,
type: "POST",
url: "controllers/c_ajax_notification.php",
data: "ordre=check_new_notification",
success: function(msg){
if(msg != 'NAN'){
var t = msg.split('***');
$('.sNotification').html(t[0]);
$('.ul-notification').html(t[1]);
$('.alert-notification').css('display','block');
}else{
$('.sNotification').html(0);
$('.alert-notification').css('display','none');
$('.ul-notification').html('');
}
},
error: function (xhr, status) {
alert('Erreur: ' + status);
}
});
}
And this is my PHP Code:
$notification->getNewNotification("*");
if($notification->db_num_row != 0){
$listNoti = '';
while($resN = $notification->fetch_array()){
$today = new DateTime(date('Y-m-d H:i:s'));
$datNoti = new DateTime($resN['date_not_crm']);
$diff = $datNoti->diff($today);
if($diff->d == 0){
if($diff->h == 0){
if($diff->i == 0){
$intervale = 'il y a '.$diff->s.' sec';
}else{
$intervale = 'il y a '.$diff->i.' min';
}
}else{
$intervale = 'il y a '.$diff->h.' heure(s)';
}
}else{
$intervale = 'il y a '.$diff->d.' jour(s)';
}
$listNoti .= '<li>
<a onclick="link(event,\''.$resN['url_not_crm'].'\');updateEtatNoti(this,'.$resN['id_not_crm'].');" style="cursor:pointer;">
<span class="label label-icon label-success"><i class="'.$resN['icon_not_crm'].'"></i></span>
'.$notification->csNotification($resN['description_not_crm']).'
<span class="time">'.$intervale.'</span>
</a>
</li>';
}
echo $notification->getCountNewNotification().'***'.$listNoti;
}else{
echo 'NAN';
}
When I remove the notification code my application become more fast !
If your application is slowing down when you run the ajax every 3 seconds, try simplifying/shrinking the amount of work the page loaded by the ajax needs to do. Rather than reading an entire table, for example, try selecting only notifications with a "read" status of 0. That way, the .php file is faster to execute, meaning the ajax will not slow down the page as much.

How is a plugin like facebook login plugin build up?

How does the plugin communicate with the facebook server without exposing too much information.
I would like to know how I can build myself a plugin that would communicate between the website it's installed on and my website.
My knowledge is limited to HTML5, CSS3, PHP5, Javascript and some Jquery.
I realise that there could be alot of ways, I was just wandering if you could point me in the right direction, or give me an idea. (: thanks in advance!
Take a look at the easyXDM framework, which allows you to do this quite easily, and if you have a chance, read Third Party JavaScript, which explains what you want to do in detail.
Some years ago, I wrote about this topic on scriptjunkie, it's as relevant now as then (although more browsers support postMessage now).
Create an application on developers.facebook.com
Download the facebook SDK for PHP since this is what you know (https://developers.facebook.com/docs/reference/php)
Read their guideline on how to implement login (it is easy and helpful)
https://developers.facebook.com/docs/facebook-login/login-flow-for-web/
This is a sample PHP function that you can build on:
function facebook_login()
{
$user = new user();
// Call Facebook API
if (!class_exists('FacebookApiException')) {
require_once ('facebook.php');
}
$facebook = new Facebook(array(
'appId' => $app_id,
'secret' => $app_secret,
));
$fbuser = $facebook->getUser();
if ($fbuser) {
try {
// Proceed knowing you have a logged in user who's authenticated.
$me = $facebook->api('/me'); //user
$uid = $facebook->getUser();
}
catch(FacebookApiException $e) {
echo error_log($e);
return;
}
}
// redirect user to facebook login page if empty data or fresh login requires
if (!$fbuser) {
$loginUrl = $facebook - getLoginUrl(array(
'redirect_uri' => $_SERVER["HTTP_REFERER"],
false
));
$logout = $facebook->getLoginUrl();
echo $loginUrl;
return;
}
// user details
$user->name = $me['name'];
$user->email = $me['email'];
$user->fbid = $uid;
// Check user id in your database
$user->selectbyfbid();
if ($user->database->rows > 0) {
// User exist, Show welcome back message
// User is now connected, log him in
}
else {
// User is new, Show connected message and store info in our Database
// Insert user into Database.
$user->insert_fb();
}
$_SESSION["access_token"] = $facebook->getAccessToken();
login_user($user);
}
In your HTML:
<a href="#" onclick="LoadingAnimate();">
<div class="fb-login-button"
onlogin="javascript:CallAfterLogin();"
data-width="600" data-max-rows="1"
data-show-faces="false"
scope="publish_stream,email,publish_actions,offline_access">
JavaScript code:
function CallAfterLogin(){
FB.login(function(response) {
if (response.status === "connected")
{
LoadingAnimate(); //show a waiting gif or whatever
FB.api('/me', function(data) {
if(data.email == null)
{
//Facbeook user email is empty, you can check something like this.
ResetAnimate();
}else{
AjaxResponse();
}
});
}
});
}
function AjaxResponse()
{
var myData = 'connect=1&action=fb_login';
jQuery.ajax({
type: "POST",
url: "/process_user.php",
dataType:"html",
data:myData,
cache: false,
success:function(response){
if(target.length > 1)
window.location.href = target;
else
location.reload();
},
error:function (xhr, ajaxOptions, thrownError){
//$("#results").html('<fieldset style="color:red;">'+thrownError+'</fieldset>'); //Error
}
});
}
I hope this helps you start!

PHP Comet cause page reload slow

Hi I am tring to implement the comet with PHP and jquery. The comet is started on every page load. However it cause loading of any page in the website become very slow like 10 seconds, it seem to be waiting for the previous request to the server to die() at the if($elapse > 10)
But if a ajax connection connection is aborted, isn't the PHP should stop executing furher ? Any idea why reloading page become slow ?
function getPendingCheckin()
{
ignore_user_abort(false);
$iCreatedDate = $this->input->post("iLastCreateDate");
$aCheckin = [];
$prev = time();
while(! $aCheckin )
{
$aCheckin = $this->getData();
if($aCheckin || connection_aborted() == 1)
{
break;
}
else
{
sleep(1);
$elapse = time() - $prev;
if($elapse > 10)
{
die();
}
}
}
header('Content-type: application/json');
echo json_encode($aCheckin);
}
Javascript
$(window).ready(function(){
var iLastCreateDate = $('#iLastCreateDate').val();
function startGetPendingCheckin()
{
$.ajax({
type: "POST",
url: "/kc/comet/getPendingCheckin",
data: 'iLastCreateDate=' + iLastCreateDate,
error : function(msg)
{
//alert("Error get pending checkin");
},
success :function(o)
{
if(o)
{
//process data
}
startGetPendingCheckin();
}
});
}
startGetPendingCheckin();
})
No, php execution is not (always) aborted. I noticed that on heavy scripts runned on local machine.
You may fail to run 2 parallel request to php scripts due to not closed session. Usually it is auto-closed after termination of the script. With default behavior (sessions in lockable files, no manual closing) it is not possitble to have 2 simultaneous requests from the same user — the latter would be blocked by the former and will wait for its termination.
You may close session as long as you checked everything about user authorization.

Is it possible to ping a server from Javascript?

I'm making a web app that requires that I check to see if remote servers are online or not. When I run it from the command line, my page load goes up to a full 60s (for 8 entries, it will scale linearly with more).
I decided to go the route of pinging on the user's end. This way, I can load the page and just have them wait for the "server is online" data while browsing my content.
If anyone has the answer to the above question, or if they know a solution to keep my page loads fast, I'd definitely appreciate it.
I have found someone that accomplishes this with a very clever usage of the native Image object.
From their source, this is the main function (it has dependences on other parts of the source but you get the idea).
function Pinger_ping(ip, callback) {
if(!this.inUse) {
this.inUse = true;
this.callback = callback
this.ip = ip;
var _that = this;
this.img = new Image();
this.img.onload = function() {_that.good();};
this.img.onerror = function() {_that.good();};
this.start = new Date().getTime();
this.img.src = "http://" + ip;
this.timer = setTimeout(function() { _that.bad();}, 1500);
}
}
This works on all types of servers that I've tested (web servers, ftp servers, and game servers). It also works with ports. If anyone encounters a use case that fails, please post in the comments and I will update my answer.
Update: Previous link has been removed. If anyone finds or implements the above, please comment and I'll add it into the answer.
Update 2: #trante was nice enough to provide a jsFiddle.
http://jsfiddle.net/GSSCD/203/
Update 3: #Jonathon created a GitHub repo with the implementation.
https://github.com/jdfreder/pingjs
Update 4: It looks as if this implementation is no longer reliable. People are also reporting that Chrome no longer supports it all, throwing a net::ERR_NAME_NOT_RESOLVED error. If someone can verify an alternate solution I will put that as the accepted answer.
Ping is ICMP, but if there is any open TCP port on the remote server it could be achieved like this:
function ping(host, port, pong) {
var started = new Date().getTime();
var http = new XMLHttpRequest();
http.open("GET", "http://" + host + ":" + port, /*async*/true);
http.onreadystatechange = function() {
if (http.readyState == 4) {
var ended = new Date().getTime();
var milliseconds = ended - started;
if (pong != null) {
pong(milliseconds);
}
}
};
try {
http.send(null);
} catch(exception) {
// this is expected
}
}
you can try this:
put ping.html on the server with or without any content, on the javascript do same as below:
<script>
function ping(){
$.ajax({
url: 'ping.html',
success: function(result){
alert('reply');
},
error: function(result){
alert('timeout/error');
}
});
}
</script>
You can't directly "ping" in javascript.
There may be a few other ways:
Ajax
Using a java applet with isReachable
Writing a serverside script which pings and using AJAX to communicate to your serversidescript
You might also be able to ping in flash (actionscript)
You can't do regular ping in browser Javascript, but you can find out if remote server is alive by for example loading an image from the remote server. If loading fails -> server down.
You can even calculate the loading time by using onload-event. Here's an example how to use onload event.
Pitching in with a websocket solution...
function ping(ip, isUp, isDown) {
var ws = new WebSocket("ws://" + ip);
ws.onerror = function(e){
isUp();
ws = null;
};
setTimeout(function() {
if(ws != null) {
ws.close();
ws = null;
isDown();
}
},2000);
}
Update: this solution does not work anymore on major browsers, since the onerror callback is executed even if the host is a non-existent IP address.
To keep your requests fast, cache the server side results of the ping and update the ping file or database every couple of minutes(or however accurate you want it to be). You can use cron to run a shell command with your 8 pings and write the output into a file, the webserver will include this file into your view.
The problem with standard pings is they're ICMP, which a lot of places don't let through for security and traffic reasons. That might explain the failure.
Ruby prior to 1.9 had a TCP-based ping.rb, which will run with Ruby 1.9+. All you have to do is copy it from the 1.8.7 installation to somewhere else. I just confirmed that it would run by pinging my home router.
There are many crazy answers here and especially about CORS -
You could do an http HEAD request (like GET but without payload).
See https://ochronus.com/http-head-request-good-uses/
It does NOT need a preflight check, the confusion is because of an old version of the specification, see
Why does a cross-origin HEAD request need a preflight check?
So you could use the answer above which is using the jQuery library (didn't say it) but with
type: 'HEAD'
--->
<script>
function ping(){
$.ajax({
url: 'ping.html',
type: 'HEAD',
success: function(result){
alert('reply');
},
error: function(result){
alert('timeout/error');
}
});
}
</script>
Off course you can also use vanilla js or dojo or whatever ...
If what you are trying to see is whether the server "exists", you can use the following:
function isValidURL(url) {
var encodedURL = encodeURIComponent(url);
var isValid = false;
$.ajax({
url: "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D%22" + encodedURL + "%22&format=json",
type: "get",
async: false,
dataType: "json",
success: function(data) {
isValid = data.query.results != null;
},
error: function(){
isValid = false;
}
});
return isValid;
}
This will return a true/false indication whether the server exists.
If you want response time, a slight modification will do:
function ping(url) {
var encodedURL = encodeURIComponent(url);
var startDate = new Date();
var endDate = null;
$.ajax({
url: "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D%22" + encodedURL + "%22&format=json",
type: "get",
async: false,
dataType: "json",
success: function(data) {
if (data.query.results != null) {
endDate = new Date();
} else {
endDate = null;
}
},
error: function(){
endDate = null;
}
});
if (endDate == null) {
throw "Not responsive...";
}
return endDate.getTime() - startDate.getTime();
}
The usage is then trivial:
var isValid = isValidURL("http://example.com");
alert(isValid ? "Valid URL!!!" : "Damn...");
Or:
var responseInMillis = ping("example.com");
alert(responseInMillis);
const ping = (url, timeout = 6000) => {
return new Promise((resolve, reject) => {
const urlRule = new RegExp('(https?|ftp|file)://[-A-Za-z0-9+&##/%?=~_|!:,.;]+[-A-Za-z0-9+&##/%=~_|]');
if (!urlRule.test(url)) reject('invalid url');
try {
fetch(url)
.then(() => resolve(true))
.catch(() => resolve(false));
setTimeout(() => {
resolve(false);
}, timeout);
} catch (e) {
reject(e);
}
});
};
use like this:
ping('https://stackoverflow.com/')
.then(res=>console.log(res))
.catch(e=>console.log(e))
I don't know what version of Ruby you're running, but have you tried implementing ping for ruby instead of javascript? http://raa.ruby-lang.org/project/net-ping/
let webSite = 'https://google.com/'
https.get(webSite, function (res) {
// If you get here, you have a response.
// If you want, you can check the status code here to verify that it's `200` or some other `2xx`.
console.log(webSite + ' ' + res.statusCode)
}).on('error', function(e) {
// Here, an error occurred. Check `e` for the error.
console.log(e.code)
});;
if you run this with node it would console log 200 as long as google is not down.
You can run the DOS ping.exe command from javaScript using the folowing:
function ping(ip)
{
var input = "";
var WshShell = new ActiveXObject("WScript.Shell");
var oExec = WshShell.Exec("c:/windows/system32/ping.exe " + ip);
while (!oExec.StdOut.AtEndOfStream)
{
input += oExec.StdOut.ReadLine() + "<br />";
}
return input;
}
Is this what was asked for, or am i missing something?
just replace
file_get_contents
with
$ip = $_SERVER['xxx.xxx.xxx.xxx'];
exec("ping -n 4 $ip 2>&1", $output, $retval);
if ($retval != 0) {
echo "no!";
}
else{
echo "yes!";
}
It might be a lot easier than all that. If you want your page to load then check on the availability or content of some foreign page to trigger other web page activity, you could do it using only javascript and php like this.
yourpage.php
<?php
if (isset($_GET['urlget'])){
if ($_GET['urlget']!=''){
$foreignpage= file_get_contents('http://www.foreignpage.html');
// you could also use curl for more fancy internet queries or if http wrappers aren't active in your php.ini
// parse $foreignpage for data that indicates your page should proceed
echo $foreignpage; // or a portion of it as you parsed
exit(); // this is very important otherwise you'll get the contents of your own page returned back to you on each call
}
}
?>
<html>
mypage html content
...
<script>
var stopmelater= setInterval("getforeignurl('?urlget=doesntmatter')", 2000);
function getforeignurl(url){
var handle= browserspec();
handle.open('GET', url, false);
handle.send();
var returnedPageContents= handle.responseText;
// parse page contents for what your looking and trigger javascript events accordingly.
// use handle.open('GET', url, true) to allow javascript to continue executing. must provide a callback function to accept the page contents with handle.onreadystatechange()
}
function browserspec(){
if (window.XMLHttpRequest){
return new XMLHttpRequest();
}else{
return new ActiveXObject("Microsoft.XMLHTTP");
}
}
</script>
That should do it.
The triggered javascript should include clearInterval(stopmelater)
Let me know if that works for you
Jerry
You could try using PHP in your web page...something like this:
<html><body>
<form method="post" name="pingform" action="<?php echo $_SERVER['PHP_SELF']; ?>">
<h1>Host to ping:</h1>
<input type="text" name="tgt_host" value='<?php echo $_POST['tgt_host']; ?>'><br>
<input type="submit" name="submit" value="Submit" >
</form></body>
</html>
<?php
$tgt_host = $_POST['tgt_host'];
$output = shell_exec('ping -c 10 '. $tgt_host.');
echo "<html><body style=\"background-color:#0080c0\">
<script type=\"text/javascript\" language=\"javascript\">alert(\"Ping Results: " . $output . ".\");</script>
</body></html>";
?>
This is not tested so it may have typos etc...but I am confident it would work. Could be improved too...

Categories

Resources