ajax long polling crashes at page refresh\links to another page - php

i have already posted a similar question here, but failed to get a response that will fix my problem, also the problem has changed a bit so i'm re-posting and desperate to get some help!
link to previous question:
ajax long polling with mysql
CURRENT CODE:
JS(I run it from php):
$oldIDq = mysql_query("SELECT * FROM messages ORDER BY id DESC LIMIT 1");
while($oldrow = mysql_fetch_array($oldIDq)){
$oldID = $oldrow['id'];
}
$func = '
var oldID = '.$oldID.';
function wait() {
$.ajax({
type: "GET",
url: "../scripts/msg_scripts/msg.php?oldid=" + oldID,
async: true,
cache: false,
success: function (data){
if(data != \'1\'){
var json = eval(\'(\' + data + \')\');
if (json[\'msg_content\'] != "") {
alert("new meassage added");
}
oldID = json[\'oldID\'];
setTimeout(\'wait()\',1000); }
},
disconnect: function()
{
return false;
setTimeout(\'wait()\',1000);
},
error: function(XMLHttpRequest, textStatus, errorThrown){
alert("error: " + textStatus + "(" + errorThrown + ")");
setTimeout(\'wait()\',1000);
}
});
}
$(document).ready(function(){
wait();
});
';
SERVER:
$connect = mysql_connect ("localhost", "root", "")
or die ("couldnt connect");
mysql_select_db ("***") or die ("not found"); //if db was not found die
mysql_query("SET NAMES 'utf8'");
$oldID = $_GET['oldid'];
if($oldID == "") {
die('timeout');
}
else{
$result = mysql_query("SELECT id FROM messages ORDER BY id DESC LIMIT 1");
while($row = mysql_fetch_array($result))
{
$last_msg_id = $row['id'];
}
while($last_msg_id <= $oldID)
{
usleep(10000);
clearstatcache();
$result = mysql_query("SELECT id FROM messages ORDER BY id DESC LIMIT 1");
while($row = mysql_fetch_array($result))
{
$last_msg_id = $row['id'];
}
}
$response = array();
$response['msg_content'] = 'new';
$response['oldID'] = $last_msg_id;
echo json_encode($response);
}
now, i had a session running on the server side of the process and i removed it for now because i understood that long polling has a problem with sessions i also have sessions running on the page which sends the ajax request, since i removed the session my problem has improved in a way, what happens now is that i can basically click on a link on my website and exit the page and get an error, but if i do it more than 4-5 times, the browser freezes an every click on any link just reruns the ajax function and i get a different error. if i refresh the page of the request i imidetly get the second error and the browser freezes. also if that's helpful information if i close the browser and try to reopen any page of my site it doesn't load at all unless i rerun my server(working on localhost right now) also tried it with chrome and ff.
can some one please point me towards the solution?

-- Updated again to retrieve all new messages
Reading your code, you only wish to return the last message, if so then the while loops are in this case pretty useless. Do keep in mind that there might be more 'new' messages between the oldID and the last ID inserted into your database which you skip, so does this code I provide
$connect = mysql_connect ("localhost", "root", "")
or die ("couldnt connect");
mysql_select_db ("***") or die ("not found"); //if db was not found die
mysql_query("SET NAMES 'utf8'");
$oldID = trim($_GET['oldid']);
// empty response, you may fill it with a default msg
$response = array(
'msg_content' => 'none',
'oldID' => $oldID
);
// this if statement will prevent to return a valid
// JSON string to the ajax request
if(empty($oldID)) {
die('timeout');
}
else {
$result = mysql_query("SELECT id FROM messages WHERE id > ".addslashes($oldID)." ORDER BY id DESC");
$index = 1;
// check if results have new messages
if(($num_rows = mysql_num_rows($result) > 0) {
$response['msg_content'] = 'new';
while($row = mysql_fetch_array($result)) {
$response['new_msgs'][] = $row['id']
if($index == $num_rows)
$response['oldID'] = $row['id']; // set oldID to last record
}
}
echo json_encode($response);
--
To your comment on how to use session_write_close properly.
session_start();
$var_id = $_SESSION['id'];
$var_fn = $_SESSION['firstname'];
$var_ln = $_SESSION['lastname'];
$var_mail = $_SESSION['email'];
// close write to session here to release it for other sources
session_write_close();
if (!loggedin()){
header ("Location: index.php");}
if ($_GET['id']) {
$id = mysql_real_escape_string($_GET['id']);}
// you are using session here, use the localized $var_id
else if (isset($var_id)) {
$id = mysql_real_escape_string($var_id);
}
When session_start() is called, the session at that point is locked for writing to any other source, except the current scope (.php file of execution) it's in. This is to make sure that no values can be changed during the readout of session values.
From the documentation
Session data is usually stored after your script terminated without the need to call session_write_close(), but as session data is locked to prevent concurrent writes only one script may operate on a session at any time. When using framesets together with sessions you will experience the frames loading one by one due to this locking. You can reduce the time needed to load all the frames by ending the session as soon as all changes to session variables are done.
To the getting stuck problem, I think the while loop is endless, request the page from your browser http://example.com/pathto/scripts/msg_scripts/msg.php and see what happens
$counter = 0;
while($last_msg_id <= $oldID)
{
usleep(10); // changing to be a bit faster
clearstatcache();
$result = mysql_query("SELECT id FROM messages ORDER BY id DESC LIMIT 1");
$row = mysql_fetch_array($result);
$last_msg_id = $row['id'];
$counter++;
if($counter > 100)
break;
}
echo "counted: {$counter}";
exit();

Related

Ajax Setting Session ID Failing Coordination with PHP query

So I am trying to make a discussion board and I have a table of posts being queried in one column of a table on the discussion board page. I then have the buttons of those post set up to a function onclick (where I am passing the post ID and then posting it to set_id.php to set as $_SESSION['name'] = $_REQUEST['name']):
scripts.js:
function getcomments(id){
$("#success_child").empty();
$.post("discussion_topics/set_id.php", {
"name": id}).done($("#success_child").load("discussion_topics/comments.php",
function(responseTxt, statusTxt, xhr){
if(statusTxt == "error")
alert("Error: " + xhr.status + ": " + xhr.statusText);
}));
}
The problem is, although the Post ID is being set correctly, the php file being loaded will load the previously set SESSION variable that is the post ID. I have absolutely no idea why.
Basically, the SEssion variable is being set properly, however, when a new post is clicked, it will query in the comments.php the old session ID, then when you click again it will query that last one that didn't show. Basically a delay somehow. But it is not a time delay because I have tried that.
HELP!
comment.php:
<?php
session_start();
echo $_SESSION['name'];
function draw_table(){
/* draw table */
$table = '<table cellpadding="0" cellspacing="0" class="discuss_table">';
//Connect To Database
$hostname="localHost";
$username="removed";
$password="removed";
$dbname="removed";
$usertable="replys";
mysql_connect($hostname,$username, $password) or die ("<html> <script>alert('Unable to connect to database! Please try again later.'),history.go(-1)</script>");
mysql_select_db($dbname);
# Check If Record Exists
$id = $_SESSION['name'];
$query = "SELECT * FROM $usertable WHERE post_id = $id";
$result = mysql_query($query);
if($result)
{
while($row = mysql_fetch_array($result))
{
//build table for post
$date = date("M d Y h:ia e", strtotime($row["date"]));
$table.="<tr>";
$table.= "<p class=\"discussion_title\">";
$table.= "<b>".$row["title"]."</b>"."<br>";
$table.=$row["name"].", ".$date." for topic ".$row["topic"]."<br>";
$table.=$row["content"]."<br>";
$table.="<button class=\"makecomment_buttons\">Reply</button>";
$table.="</p></tr>";
}
}
//end the table
$table.= '</table>';
//all done, return result
return $table;
}
echo draw_table();
echo "<br>";
?>
set_id.php
<?php
session_start();
$_SESSION['name'] = $_REQUEST['name'];
?>

How to limit the number of user requests made within a minute

A user will request a file by number via a URL like script.php?userid=222. This example would show the record of file #222.
Now I want to limit the number of files per (remote IP) user to a maximum of 5 different records in a minute. However, the user should be able to access the same id record any number of time.
So the user could access file #222 any number of times, but if the (remote IP) user accesses more than 5 other different records in a minute, then it should show an error.
For example, suppose within a minute the following requests are made:
script.php?userid=222
script.php?userid=523
script.php?userid=665
script.php?userid=852
script.php?userid=132
script.php?userid=002
then at the last request it should show the error message.
Here is the basic code:
$id = $_GET['userid'];
if (!isset($_GET['userid']) || empty($_GET['userid'])) {
echo "Please enter the userid";
die();
}
if (file_exists($userid.".txt") &&
(filemtime($userid.".txt") > (time() - 3600 * $ttime ))) {
$ffile = file_get_contents($userid.".txt");} else {
$dcurl = curl_init();
$ffile = fopen($userid.".txt", "w+");
curl_setopt($dcurl, CURLOPT_URL,"http://remoteserver.com/data/$userid");
curl_setopt($dcurl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($dcurl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
curl_setopt($dcurl, CURLOPT_TIMEOUT, 50);
curl_setopt($dcurl, CURLOPT_FILE, $ffile);
$ffile = curl_exec($dcurl);
if(curl_errno($dcurl)) // check for execution errors
{
echo 'Script error: ' . curl_error($dcurl);
exit;
}
curl_close($dcurl);
$ffile = file_get_contents($userid.".txt");
}
Instead of relying on the IP address, you could use the session mechanism. You can create a session scope via session_start(), and then store information that sticks with the same user session.
I would then suggest to keep in this session scope the list of unique IDs used in previous requests that user made, together with the time of the request, ignoring any repeated requests, which are always allowed. As soon as this list contains 5 elements with a time stamp within the last minute and a new ID is requested, you show the error and refuse the lookup.
Here is the code that does this. You should place it right after you have checked the presence of the userid argument, and before the retrieval of the file contents:
// set the variables that define the limits:
$min_time = 60; // seconds
$max_requests = 5;
// Make sure we have a session scope
session_start();
// Create our requests array in session scope if it does not yet exist
if (!isset($_SESSION['requests'])) {
$_SESSION['requests'] = [];
}
// Create a shortcut variable for this array (just for shorter & faster code)
$requests = &$_SESSION['requests'];
$countRecent = 0;
$repeat = false;
foreach($requests as $request) {
// See if the current request was made before
if ($request["userid"] == $id) {
$repeat = true;
}
// Count (only) new requests made in last minute
if ($request["time"] >= time() - $min_time) {
$countRecent++;
}
}
// Only if this is a new request...
if (!$repeat) {
// Check if limit is crossed.
// NB: Refused requests are not added to the log.
if ($countRecent >= $max_requests) {
die("Too many new ID requests in a short time");
}
// Add current request to the log.
$countRecent++;
$requests[] = ["time" => time(), "userid" => $id];
}
// Debugging code, can be removed later:
echo count($requests) . " unique ID requests, of which $countRecent in last minute.<br>";
// if execution gets here, then proceed with file content lookup as you have it.
Deleted session cookies...
Sessions are maintained by cookies on the client. The user may delete such cookies, an so get a new session, which would allow the user to make new requests without regard of what was previously requested.
One way to get around this is to introduce a cool-down period for each new session. For instance, you could have them wait for 10 seconds before a first request can be made. To do that, replace in above code:
if (!isset($_SESSION['requests'])) {
$_SESSION['requests'] = [];
}
By:
$initial_delay = 10; // 10 seconds delay for new sessions
if (!isset($_SESSION['requests'])) {
$_SESSION['requests'] = array_fill(0, $max_requests,
["userid" => 0, "time" => time()-$min_time+$initial_delay]
);
}
This is of course less user friendly as it affects any new session, also of users who are not trying to cheat by deleting cookies.
Registration
The better way is to only allow the lookup services to registered users. For this you must provide a user database and authentication system (for example password based). The requests should be logged in the database, keyed by the user's ID. If then a new session starts, the user must first authenticate again, and once authenticated the request history is retrieved from the database. This way the user cannot cheat around it by changing something on their client configuration (IP address, cookies, employing multiple devices in parallel, ...)
<?php
// session_start();
// session_destroy();
// exit;
echo index();
function index()
{
$id = rand(000,020);
$min_time = 60;
$max_requests = 5;
// $id = 0;
session_start();
$repeat = false;
if(!isset($_SESSION["countRecent"]) && !isset($_SESSION["countRecent"]) && !isset($_SESSION["countRecent"])){
$_SESSION["countRecent"] = 1;
$_SESSION["time"] = time();
$_SESSION['userid'][] = $id;
}else{
if ($_SESSION["countRecent"] >= $max_requests) {
if(!in_array($id,$_SESSION['userid'])){
if ($_SESSION["time"] <= time() - $min_time) {
$_SESSION["countRecent"] = 1;
$_SESSION["time"] = time();
}else{
return("Too many requests in a short time wait ". ( $_SESSION["time"] - (time() - $min_time) )). " Seconds";
}
}
}else{
if(!in_array($id,$_SESSION['userid'])){
$_SESSION["countRecent"] = $_SESSION["countRecent"] + 1;
$_SESSION['userid'][] = $id;
}
}
}
return "Your Result goes here.. id: $id Counts: ". $_SESSION["countRecent"];
}
Try this. Fast , low memory usage
But not secure;
also use database
<?php
$conn = mysqli_connect("localhost", "root", "","db_name") or die("Could not connect database");
$id = rand(0,99);
// $id = 100;
echo index($id);
function index($id,$user=1,$ip='192.168.0.10',$max_requests = 5,$min_time = 20)
{
global $conn;
$time = time();
$req = "INSERT INTO `limit_api_by_ip2`(`id`, `ip`, `time`, `user`, `req`)
VALUES (null,INET_ATON('$ip'),'$time','$user',1)
ON DUPLICATE KEY UPDATE req=req+1;";
$req2 = "INSERT INTO `limit_api_by_ip2`(`id`, `ip`, `time`, `user`, `req`)
VALUES (null,INET_ATON('$ip'),'$time','$user',1)
ON DUPLICATE KEY UPDATE req=1,`time`='".time()."' ;";
$reqid = "INSERT INTO `limit_api_by_ip2_count`(`id`, `user`, `ids`) VALUES (null,'$user',$id)";
$getid = "SELECT `ids` FROM `limit_api_by_ip2_count` WHERE user = $user and ids = $id limit 1;";
$gettime = "SELECT `time`,`req` FROM `limit_api_by_ip2` WHERE user = $user and ip = INET_ATON('$ip') limit 1;";
// $id = 0;
$q = mysqli_query($conn,$getid);
$c = mysqli_num_rows($q);
if($c==0){
$get_time = mysqli_query($conn,$gettime);
$c1 = mysqli_num_rows($get_time);
if($c1==0){
mysqli_query($conn,$req);
mysqli_query($conn,$reqid);
}else{
$row = mysqli_fetch_row($get_time);
if ($row[1] >= $max_requests) {
if ($row[0] <= (time() - $min_time)) {
mysqli_query($conn,$req2);
mysqli_query($conn,$reqid);
}else{
return "Too many requests in a short time wait ".($row[0]-(time() - $min_time))." Seconds";
}
}else{
mysqli_query($conn,$req);
mysqli_query($conn,$reqid);
}
}
}else{
}
if(isset($row[1]))
{
$cc = "Counts: ".$row[1];
$dd = "new id: $id";
}else{
$cc = '';
$dd = "old id: $id";
}
return "Your Result goes here.. $dd ".$cc;
}

Failed to assign variable taken from database to json array

I try to get the data from database to display data via ajax but failed to worked. It's partially working because data from mysql make this thing failed to function.
Here is my funds_transfer_backend.php page. This page will assign variable to json array.
session_start();
if(!isset($_SESSION['myusername']))
{
header("Location: ../index.html");
die();
}
include("../connect.php");
$myusername = $_SESSION['myusername'];
$sql="SELECT client_id FROM `client` WHERE username='$myusername'";
$result=mysqli_query($conn, $sql);
while ($row=mysqli_fetch_row($result)){
$id = $row['0'];
}
$index_num = $_POST['index_num'];
$to_account_num = $_POST['recipient'];
$amount = $_POST['amount'];
if ($amount == '' || $to_account_num == '' || $index_num == -1){
//echo "Please complete the form!";
$response = -1;
}
else {
// check account number exist
$query2 = "SELECT 1 FROM account WHERE id='$to_account_num' LIMIT 1";
if (mysqli_num_rows(mysqli_query($conn, $query2))!=1) {
//echo "Recipient account number is invalid!";
$response = -2;
}
else {
$query2 = "SELECT client.name, client.email FROM account JOIN client USING (client_id) WHERE account.id = '$to_account_num' LIMIT 1";
$result=mysqli_query($conn, $query2);
while($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) {
$name = $row['name'];
$email = $row['email'];
}
$response = 1;
}
} // check account num else bracket
$display = array('response' => $response, 'name' => $name);
echo json_encode($display);
However if I remove 'name' => $name from array the #stage div will trigger like image below:
Here is my funds_transfer.php page
<script type="text/javascript">
function update() {
var two = $('#index_num').val();
var three = $('#recipient_box').val();
var five = $('#amount_box').val();
$.post("funds_transfer_backend.php", {
index_num : two,
recipient : three,
amount : five
},function(data){
if (data.response==-1) {
$('#stage').show().html("Please complete the form!");
}
$('#stage').delay(2000).fadeOut();
},"json");
}
</script>
...other code goes here
<div id="stage" style="background-color:#FF6666; padding-left:20px; color: white;"></div>
<div id="confirm" style="background-color:#FF7800; padding-left:20px; color: white;"></div>
I try to check the data from db whether it exist using manual form method="post" and I can see the name being echo. Any help is appreciated and thanks in advance.
When your response is -1, your $name variable is undefined. So php could show a warning (depending on your settings) and you are trying to add an undefined variable to your array. This will invalidate your output / json.
You can set for example:
$name = '';
at the start of your script or check whether the variable is set with isset($name) before you try to use it to avoid these problems.
There are of course other solutions, like outputting your -1 directly and exiting the script there.
I always initialize my variables.
$myusername = isset($_SESSION['myusername']) ? $_SESSION['myusername'] : false;
Then you can safely do:
if ($myusername) {} without throwing warnings.
I do this weather I get my data from a db, post/get/session or json/ajax.
It takes a little extra time upfront but removes dozens of errors in the back end so you net more time.

While parsing xml/json, skip page if error message received

I have following issue. I am parsing an xml feed with multiple pages and there is no way to understand how many they are (I have a variavle set in the xml url, so for each variable there are random number of pages). All I know is that the number can not exceed 50. Now I have a script that autoincrement the variable for the page number starting at 1 and up to 50.
Let's say, that the link has total of 26 pages. With my script I will continue to send requests until the scripts gets to page 50. Than it changes the first variable and starts again from 1 to 50. For the first link, from page 27 forward the xml will return followwing:
<response>
<status>error</status>
<code>400</code>
<message>Incorrect Request Headers</message>
</response>
How can I make so when the scipt receive this message, to stop the autoincrement and continue by changing the first variable and start again at 1? The code now is:
$query = "SELECT * FROM table_name ORDER BY id ASC";
$result = mysql_query($query) or die(mysql_error());
while ($row = mysql_fetch_array($result)) {
if($row['row_name'] == '') {
$variable1 = 0;
}
else {
$variable1 = $row['row_name'];
}
$page = 0;
do {
$page++;
$result = apiCall('option1', 'option2', array('option3' => $variable1, 'page' => $page));
usleep(1000);
$res = json_decode($result);
foreach ($res->node1->node2 as $item) {
//define variable for insertion in MySQL
$sql1 to insert the variables
if (!mysql_query($sql1,$con1))
{
die('Error: ' . mysql_error());
}
}
}
while ($page<=50);
}
In the above code, only the $variable1 and $page are variables. All options (1, 2 and 3) are predefined and stay the same. I.e. I need when the script gets the error message to start again from 1 with next value of $variable1.
OK. Here is the code I played around:
$query = "SELECT * FROM table_name ORDER BY id ASC";
$result = mysql_query($query) or die(mysql_error());
while ($row = mysql_fetch_array($result)) {
if($row['row_name'] == '') {
$variable1 = 0;
}
else {
$variable1 = $row['row_name'];
}
$page = 1;
do {
$result = apiCall('option1', 'option2', array('option3' => $variable1, 'page' => $page));
usleep(1000);
$res = json_decode($result);
if ($res->status == 'error') {
break 2;
}
foreach ($res->node1->node2 as $item) {
//define variable for insertion in MySQL
$sql1 to insert the variables
if (!mysql_query($sql1,$con1))
{
die('Error: ' . mysql_error());
}
}
$page++;
}
while (0);
}
The problem is that it stops the script execution at some point. Can not understand why.

HTML 1 click delete from MySQL database

how would I create a link that would when clicked erase a record from a MySQL database based on the id of that item? using php if possible.
edit// The link will require authentication in order to view
Thanks
EDIT: I somehow got it in my head that you were looking for an ajax solution, but it seems that I was wrong. Still, I'll leave this here in case it's useful.. #David's solution is the way to go based on what you asked.
This should get you started. The client script uses jQuery:
<a id="item_45" href="#" class=".btnDelete">Delete this</a>
<a id="item_100" href="#" class=".btnDelete">Delete this</a>
<script>
$(document).ready(function() {
$("a.btnDelete").click(function() {
// get the number from the ID after the '_'. Remember, IDs cannot start with numbers
var itemId = this.id.split("_")[1];
// ask the server for some json
// if the 'status' offset is set to '1', the delete was successful
// otherwise, display what's in the 'error' offset
$.post('deleteStuff.php', {id: itemId}, function(json) {
if(json.status == "1") {
alert("delete was successful");
} else {
alert(json.error);
}
}, "json");
return false;
});
});
</script>
<?php
$id = $_POST['itemId'];
// delete corresponding record from database
if($delete_successful) {
$data = array('status' => '1');
} else {
$data = array('error' => 'Could not delete item. Please contact support';
}
echo json_encode($data);
?>
Put the id in the query string
Read the value from $_GET
Construct the SQL query
Send it
… or don't. Having a bot or a pre-fetching cache delete your database is a really bad idea. Use forms and $_POST. Get requests are supposed to be safe.
<?php
if (isset($_GET['delete']) && preg_match('/[0-9]+/', $_GET['delete'])) {
$id = (int) $_GET['delete'];
$sql = "DELETE FROM $table WHERE id = '$id' LIMIT 1";
$res = mysql_query($sql);
$del = mysql_affected_rows();
}
if ($del) {
echo '<p>Rows deleted: <strong>'.$del.'</strong></p>';
}
// loop over your records here, outputting an <a> tag for each record
// this could be an interactive data-grid table or whatever
echo '<p>Delete record #1</p>';
echo '<p>Delete record #2</p>';

Categories