Delaying browser Ajax output (LongPolling) - javascript

I'm trying to complete a connection using Long Polling, where the browser sends a request to the server and to be awaiting a response. To prevent this door is infinitely open, I created a routine that every 10 seconds the server sends an empty response to the browser, stating that there was nothing yet.
It's all working perfectly, had no problems related to that.
My problem is that when the user clicks on a link on the page, the browser waits for the answer call for power upgrade, or can take up to 10-sec. This makes it appear that the tool is slow.
Does anyone have any idea how to solve this?
Image:
Image:
Follows the JavaScript function used to make the call:
function loadJSON() {
if(libera) {
var data_file = http + "bibliotecas/longpolling/notificacoes.php";
var data = {};
data.n = long_n;
data.u = userchat;
data.m = msgchat;
data.c = chatUsuario;
http_request.onreadystatechange = function() {
if(http_request.readyState == 4 && http_request.status == 200) {
try {
var jsonObj = JSON.parse(http_request.responseText);
var qtd = jsonObj.funcao.length;
if(qtd > 0) {
var funcao = "";
for(var key in jsonObj.funcao) {
funcao = jsonObj.funcao[key];
MontarFuncao(eval(funcao),jsonObj.metodo[key]);
}
}
}
catch (e) {
//alert('Erro - '+ http_request.responseText);
}
loadJSON();
}
}
var string = JSON.stringify(data);
http_request.open("POST", data_file, true);
http_request.setRequestHeader("Content-Type", "application/json; charset=UTF-8");
http_request.setRequestHeader("Content-length", string.length);
http_request.setRequestHeader("Connection", "close");
http_request.send(string);
return;
}
}
Follows the PHP function responsible for staying open expecting some changes in the database:
ob_start();
$json = json_decode(file_get_contents(`php://input`));
while($x < 5) {
if(time() >= (15 + $_SERVER['REQUEST_TIME']) || connection_aborted()) {
echo str_pad(NULL,1);
die(json_encode(array()));
flush();
ob_flush();
break;
}
//Query DB
if(count($retorno) > 0) {
flush();
ob_flush();
echo json_encode($retorno);
exit;
}
else {
flush();
sleep(2);
$x++;
}
}

Related

$.post never receives a response

I'm a fairly inexperienced coder, and am seeking help on why I'm not receiving a response to my $.post command.
From the output, (i think) the post is correctly submitting the PHP page, and the PHP correctly creates a JSON file with the values I expect. The issue is that my callback never seems to fire.
I never receive a log message of "Function Response", therefore, I don't think the post is ever entering the callback.
I've read lots and lots, and attempted a bunch of solutions, including some AJAX. But after about 10 hours, I'm stumped. My $.post is based on the this guide: Save JavaScript variables to PHP/MySQL DataBase Securely with Ajax Post
Thanks for any help you can shed on this.
I'm testing the code on a Windows most recent WAMP Server.
index.php (relevant bit)
$('#radarDropdown').change(function () {
currentRadarId = $('#radarDropdown').val();
var radSel = document.getElementById('radarDropdown');
var currentRadarName = radSel.options[radSel.selectedIndex].text;
document.getElementById('radarSelectedLabel').innerHTML = currentRadarId;
document.getElementById('radarSelectedName').innerHTML = currentRadarName;
getBacks(currentRadarName, processResponse);
// getBackground(currentRadarName);
console.log('Start request');
// document.getElementById('returnBackground2').innerHTML = back1;
// get background image filename for this radar.
});
function getBacks(currentRadarId, callbackFn) {
console.log('Enter getBacks');
$.post(
"getBackgrounds.php",
{radarBOMId: currentRadarId},
function(response) {
console.log('function response');
processResponse(response);
},'json');
};
function processResponse(response){
console.log('Entered processResponse');
console.log(response);
var backgroundFile = response.background;
var locationsFile = response.locations;
var roadsFile = response.roads;
var riversFile = response.riverBasins;
var railFile = response.rail;
var rangeFile = response.range;
var topoFile = response.topography;
var catchFile = response.catchments;
var wthrDistrictsFile = response.wthrDistricts;
var waterwaysFile = response.waterways;
document.getElementById('returnBackground2').innerHTML = backgroundFile;
};
});
getBackrounds.php:
<?php
header('Content-type: application/json');
require_once('dbconnect.php');
$typesArray = array(
'background',
'catchments',
'locations',
'rail',
'range',
'riverBasins',
'roads',
'topography',
'waterways',
'wthrDistricts',
);
$idval = mysqli_real_escape_string($connection, $_POST['radarBOMId']);
foreach ($typesArray as $i => $value) {
$sql = 'SELECT backfilename, backtype FROM InUseRadarsBackgroundsView WHERE productidbom ="'. $idval. '" and backtype = "'.$value.'"';
$result = $connection->query($sql);
$response = array();
if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
$response[$value] = $row["backfilename"];
//console.log('Processed row ' & $i);
}
echo json_encode($response);
} else {
echo " 0 results";
}
}
?>
POST response:
{"background":"IDR503.background.png"}{"catchments":"IDR503.catchments.png"}{"locations":"IDR503.locations.png"}{"rail":"IDR503.rail.png"}{"range":"IDR503.range.png"}{"riverBasins":"IDR503.riverBasins.png"}{"roads":"IDR503.roads.png"}{"topography":"IDR503.topography.png"}{"waterways":"IDR503.waterways.png"}{"wthrDistricts":"IDR503.wthrDistricts.png"}
This is not the complete answer, but try to add other callbacks (e.g. fail callback) to check if some errors occur when you make this POST. Here is an example of how this can be done :
$.post( "example.php", function(data) {
alert( "success" );
})
.fail(function(jqXHR, textStatus) {
alert( "Request failed: " + textStatus );
})
.always(function() {
alert( "finished" );
});

How to retrieve a php form with AJAX at specific time spans

I want to display a form with a script I adapted from this question. The script is in a file I wrote called queries.js, and its purpose is to print the content of a php form called "dbMinAlert.php" in a div like this <div id="recentExits" name="recentExits"></div> located in my project's index, I tried invoking getNewData(); in my index.php file using this tag <body onLoad="getNewData()"> but it doesn't seem to do anything at all.
var data_array = ''; // this is a global variable
function getNewData() {
$.ajax({
url: "dbMinAlert.php",
})
.done(function(res) {
data_array = res; // the global variable is updated here and accessible elsewhere
getNewDataSuccess();
})
.fail(function() {
// handle errors here
})
.always(function() {
// we've completed the call and updated the global variable, so set a timeout to make the call again
setTimeout(getNewData, 2000);
});
}
function getNewDataSuccess() {
//console.log(data_array);
document.getElementById("recentExits").innerHTML=data_array;
}
getNewData();`
---This php code works and it actually does what I expect it to do. The real problem is the javascript, for all I care the next php form could print a "Hello world" message, but I want it displayed inside the div I placed in my index, without having to post a thing to dbMinAlert.php.
define("HOST", "localhost");
define("DBUSER", "root");
define("PASS", "password");
define("DB", "mydb");
// Database Error - User Message
define("DB_MSG_ERROR", 'Could not connect!<br />Please contact the site\'s administrator.');
$conn = mysql_connect(HOST, DBUSER, PASS) or die(DB_MSG_ERROR);
$db = mysql_select_db(DB) or die(DB_MSG_ERROR);
$query = mysql_query("
SELECT *
FROM outputs, products
WHERE products.idProduct=outputs.idProduct
ORDER BY Date DESC, Time DESC limit 5
");
echo '<ul class="news">';
while ($data = mysql_fetch_array($query)) {
$date = date_create($data['Date']);
$time = date_create($data['Time']);
echo '<li><figure><strong>'.date_format($date,'d').'</strong>'.date_format($date,'M').date_format($date,'Y').'</figure>'.$data["idProduct"]." ".$data['prodName'].'</li>';
}
echo '</ul>';
You have to execute the function for the first time.
getNewData();
It could be the way you are returning the result from php. Instead of doing multiple echo, could you first assign your result in single php variable and finally do single echo.
$result = '<ul class="news">';
while ($data = mysql_fetch_array($query)) {
$date = date_create($data['Date']);
$time = date_create($data['Time']);
$result = $result + '<li><figure><strong>'.date_format($date,'d').'</strong>'.date_format($date,'M').date_format($date,'Y').'</figure>'.$data["idProduct"]." ".$data['prodName'].'</li>';}
$result = $result + '</ul>';
echo $result;
I found a solution in this question and my code ended up Like this.
I just had to invoke the function in my index by typing <body onload="return getOutput();">
JavaScript
//Min-Max Alerts
// handles the click event for link 1, sends the query
function getOutput() {
getRequest(
'dbMinAlert.php', // URL for the PHP file
drawOutput, // handle successful request
drawError // handle error
);
return false;
}
// handles drawing an error message
function drawError() {
var container = document.getElementById('recentExits');
container.innerHTML = 'Bummer: there was an error!';
}
// handles the response, adds the html
function drawOutput(responseText) {
var container = document.getElementById('recentExits');
container.innerHTML = responseText;
}
// helper function for cross-browser request object
function getRequest(url, success, error) {
var req = false;
try{
// most browsers
req = new XMLHttpRequest();
} catch (e){
// IE
try{
req = new ActiveXObject("Msxml2.XMLHTTP");
} catch(e) {
// try an older version
try{
req = new ActiveXObject("Microsoft.XMLHTTP");
} catch(e) {
return false;
}
}
}
if (!req) return false;
if (typeof success != 'function') success = function () {};
if (typeof error!= 'function') error = function () {};
req.onreadystatechange = function(){
if(req.readyState == 4) {
return req.status === 200 ?
success(req.responseText) : error(req.status);
}
}
req.open("GET", url, true);
req.send(null);
return req;
}

How to send curl upload progress to ajax to be displayed

What I am trying to do is upload the file/files information to upload.php using ajax, then uploading the same information again to a remote server by curl to remoteUpload.php. Finally in remoteUpload.php file I perform the actual upload of the file/files.
When doing the first step -> upload the file/files information to upload.php I display a progress bar of this step using ajax.
But the when doing the second step -> upload the same information again to remote server using curl to remoteUpload.php the progress bar is not displayed, and this is my problem.
How to display the progress bar for second step by ajax ?
Javascript:
var upload_btn = document.getElementById('upload_file');
var result = document.getElementById('result');
upload_btn.onclick = function () {
var uploadInput = document.getElementsByName('file[]')[0];
if (uploadInput.files.length > 0) {
console.clear();
var ajax = new XMLHttpRequest();
var inputFileData = formData(uploadInput);
ajax.onreadystatechange = function () {
if (ajax.readyState == 4 && ajax.status == 200) {
var json = JSON.parse(ajax.responseText);
result.innerHTML = json.text;
}
};
ajax.upload.addEventListener('progress', function (e) {
result.innerHTML = Math.round(e.loaded / e.total * 100) + "%";
});
ajax.open("post", "upload.php");
ajax.send(inputFileData);
}
};
function formData(inputFileObj) {
var formData = new FormData;
var inputFile = inputFileObj.files;
if (inputFile.length > 0) {
for (i = 0; i < inputFile.length; i++) {
formData.append(inputFileObj.name, inputFile[i]);
}
}
return formData;
}
PHP: (upload.php)
function progressCallback($dltotal, $dlnow, $ultotal, $ulnow) {
static $last;
$progress = #round($ulnow / $ultotal * 100);
if($last < $progress) echo json_encode(array('text' => $progress));
flush();
$last = $progress;
}
if (strtolower($_SERVER['REQUEST_METHOD']) == 'post' && !empty($_FILES)) {
foreach ($_FILES['file']['tmp_name'] as $index => $tmpFileName) {
if ($_FILES['file']['error'][$index] > 0) {
$text = "A file did not uploaded correctly.";
return false;
}
$ch = curl_init("http://serverfiles/remoteUpload.php");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_NOPROGRESS, false);
curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, 'progressCallback');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, array('fileupload' => '#' . $tmpFileName));
$text = curl_exec($ch);
}
}
echo json_encode(array('text' => $text));
exit;
PHP: (remoteUpload.php)
if (move_uploaded_file($_FILES['fileupload']['tmp_name'], "files/" . $_FILES['fileupload']['name']))
echo "The file has been uploaded.";
else
echo "error";
You can save in progressCallback() to $_SESSION your $progress and from js side after "first step" upland complete run setIntevral(/*ajax*/) make ajax requests to server get $_SESSION['progress] and display second progress bar(or load first progress barr till 50% and continue load second 50%) in your form and when it complete call clearInterval()
DETAILED ANSWER
Explanation: we will count progress in following logic. If we have uploaded 5 files at once (as in your case seems uploaded was multi file) then we will divide 100% by 5 and will increase by 25% progress during one file curl submit, for this you need following 5 modifications
1) call somewhere above session_start() in your upload.php if it not done
2) save to session total files count and current processing file index
// Saveing total amount of uploaded files
$_SESSION['UP_total_count'] = count($_FILES['file']);
foreach ($_FILES['file']['tmp_name'] as $index => $tmpFileName) {
...
// Saving current index of uploaded file
$_SESSION['UP_current_index'] = ($index+1);//+1 as it starts from 0
}
3) save in progressCallback function current progress number in 0-100 format
function progressCallback($dltotal, $dlnow, $ultotal, $ulnow) {
...
$_SESSION['UP_current_progress'] = $progress;
}
4) create new getUploadProgress.php and return json encoded progress infromation from session
session_start();
echo json_encode( array(
'total_count' => $_SESSION['UP_total_count'],
'current_index' => $_SESSION['UP_current_index'],
'current_progress' => $_SESSION['UP_current_progress'],
) );
5) add in your ajax.onreadystatechange setInteval function call, and define in your js global variable progressSetInterval
....
var progressSetInterval = null;// Global
ajax.onreadystatechange = function () {
if (ajax.readyState == 4 && ajax.status == 200) {
...
progressSetInterval = setInterval(function(){
$.ajax({
type: "POST",
url: "getUploadProgress.php",
success: function(data){
// Calculating progress based on 100 25 logic explained above
var progressPart = 100 / data['total_count'];
var currProgress =
(data['total_count'] - data['current_index']) * progressPart;
currProgress += (progressPart/100) * data['current_progress'];
// You can display progress somehow, apped to div or show prgoress...
console.log( "Second progress: " + currProgress);
// if currProgress is 100% removing setinterval
if( currProgress >= 100 ){
clearInterval( progressSetInterval );
}
},
dataType: 'json'
});
}, 1000);
}
};
NOTE: during usage of this example code of course there will be needed additional rounds, JS/PHP functions addition, variable adjustments or some logical adjustments for more effectiveness, but basically this is logic of one option which you can use

Pull working PHP file (with scripts) into div using JavaScript without iframes

Working within system constraints, I needed a way to put working code from a local .php or .html into a target div without additional libraries, jfiddle, iframes, etc. (jquery was fine)
Here are my failed attempts.
First part of file
This is some page!
<script>$("#fruit").click(function(){Expand01("fruit.php"); return false;});</script>
A pretty good page...
<script>$("#orange").click(function(){Expand01("orange.php"); return false;});</script>
I like this page
<script>$("#tomato").click(function(){Expand01("tomato.php"); return false;});</script>
Later in file (after Expand01 function declared)
<div id="thisdiv"></div>
Attempt 1
<script> function Expand01(targetUrl){
document.getElementById('thisdiv').style.display = "block";
document.getElementById('thisdiv').innerHTML = targetUrl;
document.getElementById('thisdiv').append = '<div id="thatdiv"></div>';
} </script>
Attempt 2
<script> function Expand01(targetUrl){
var myTargetUrl = new XMLHttpRequest();
document.getElementById('thisdiv').style.display = "block";
myTargetUrl.open("GET", targetUrl, true);
myTargetUrl.setRequestHeader("Content-Type","text/plain");
myTargetUrl.send("");
document.getElementById('thisdiv').innerHTML = myTargetUrl.responseText;
document.getElementById('thisdiv').append = '<div id="thatdiv"></div>';
} </script>
Attempt 3
<script> function Expand01(targetUrl){
document.getElementById('thisdiv').innerHTML = $.get(targetURL);
} </script>
Attempt 4
<script> function Expand01(targetUrl){
var myFile = getHTTPObject();
myFile.onreadystatechange = function() {
if(request.readyState == 4) {
if(myFile.status == 200 || request.status == 304) {
var targetDiv = document.getElementById('thisdiv');
targetDiv.innerHTML = myFile.responseText;
} else {
alert("Failure");
}
}
}
myFile.open("GET", targetUrl, true);
myFile.send(null);
} </script>
This is the method I use when doing this for ajax applications. It also allows for the usage of $_SESSION[] variables as well as any Javascript or jQuery located in the php file you are pulling into your container.
jQuery:
$.post('pageloader.php', {url: 'path/to/file.php'}, function(data){
var o = $.parseJSON(data);
if(o.status == 1){
$('#yourContainer').html(o.markup);
} else {
alert(o.message);
}
});
PHP: (pageloader.php)
$url = $_POST['url'];
$response = array();
ob_start();
include("markup/" . $url); // Replace or remove '"markup/" . ' depending on file locations
$response['markup'] = ob_get_clean();
if($response['markup']){
$response['status'] = 1;
} else {
$response['status'] = 0;
$response['message'] = 'There was an issue loading the page.';
}
echo json_encode($response);
Hope this helps!

Check the status of a file move by comparing directory sizes

i'm trying to use PHP to move some files, as it does that I have a script which will compare the source location with the destination location and work out the difference.
It all starts with a button like so:
<input type="button" class="upload_button" onClick="upload_images('drive_<?=$x["letter"]?>');start_upload_progress()" value="<?=$x["name"]?>"/>
This then starts these two scripts:
function upload_images(x) {
var url = "http://localhost:1234/ppa/php/process_upload.php?x="+x
doc("upload_iframe").src = url;
}
First of all it will change a hidden iframe url to the PHP script and send over the drive letter.
function start_upload_progress() {
upload_progress("http://localhost:1234/ppa/php/upload_progress.php",function() {
doc("upload_bar").innerHTML = this;
if(this != 100) {
//doc("upload_bar").innerHTML = x;
setTimeout(start_upload_progress(),1000);
}
});
}
Next the above script will start, the console.log is simply for me to see if it's working, although I do not see "start" in my console. This function uses a callback, the below code simply loads a PHP script and returns the result. If the result is less than 100 then the call is made again every couple of seconds.
function upload_progress(url, callback) {
var http = getHTTPObject();
http.onreadystatechange = function() {
if (http.readyState == 4 && http.status == 200) {
if (http.responseText == "true") {
//window.location.replace("http://localhost:1234/ppa/rotate.php");
}
callback.call(http.responseText);
}
};
http.open("GET", url, true);
http.send();
}
Below is the PHP script, this was working when I set the $_SESSION['tmp'] variable manually.
<?php
session_start();
//If session has been created then ready to start progress bar
if (isset($_SESSION['tmp'])) {
if ($_SESSION['tmp'] != "true") {
$session_date = str_replace("/","",$_SESSION['session_date']);
$tmp = explode("_", $_SESSION['tmp']);
$upload_number = $tmp[1];
$drive = $tmp[0];
//get paths
$destination = $_SESSION['ROOT_PATH']."data/images/".str_replace("/","",$_SESSION['session_date'])."/".$upload_number."/";
$source = $drive.":/DCIM/";
if (is_dir($destination) && is_dir($source)) {
$source_size = foldersize($source);
$destination_size = foldersize($destination);
echo "Percentage: ".floor(($destination_size / $source_size * 100));
}
} else {
echo "done: ".$_SESSION['tmp'];
}
}
function foldersize($path) {
$total_size = 0;
$files = scandir($path);
$cleanPath = rtrim($path, '/'). '/';
foreach($files as $t) {
if ($t<>"." && $t<>"..") {
$currentFile = $cleanPath . $t;
if (is_dir($currentFile)) {
$size = foldersize($currentFile);
$total_size += $size;
}
else {
$size = filesize($currentFile);
$total_size += $size;
}
}
}
return $total_size;
}
?>
The $_SESSION['tmp'] variable is created just before the files begin to move, it seems like I can't access this session variable until the code has finish executing...
It is created here, at the top of the file moving script:
if (isset($drive)) {
$x = explode("_", $drive);
$x = $x[1];
//Check if connected file exists
if(file_exists($x.":/connected.txt")) {
$file = file_get_contents($x.":/connected.txt");
if ($file != false) {
$file_code = split(":", $file);
//Check if the file has the correct pass code
if($file_code[0] == $code) {
$_SESSION['tmp'] = $x."_".$drive;
When the files have finished moving the variable is set to "true", which seems to be the only value I can get...
Any ideas why my "start_upload_progress" function is not working? The console.log isn't running and I don't think the $_SESSION['tmp'] variable is setting until the file moving script has finished.
Edit 2:
I have got the script running, it compares the source and the destination and updated the innerHTML of the div with the difference. Only issue is that it only seems to work when I move the files from one place to the other manually.
The upload_progress script seems to freeze whilst the files are being moved, it should run at the same time to check the progress.
I have watched the files disappear from the source folder as well but all at the same time, shouldn't they move one by one as the scripting is only moving them one by one...

Categories