I am trying to implement a progressbar when a user executes find request in my web application(php/js/html).
When the user executes the find request, application executes php script using ajax, this script periodically stores its progress in session variable.
What I tried to do is to poll the server with another ajax request to ask for the session progress variable, but the variable does not exist.
Why is this happening, is this not possible using php sessions?
Thanks
JS logic:
// When the user selects interested object, find it on the server
$(document).on('change', '#findStreamer', function()
{
$streamerId = $(this).val();
$streamerName = $('#findStreamer option[value="'+$streamerId+'"]').text();
console.log('findDB', $streamerId, $streamerName);
addProgressBar();
getProgress();
$.ajax({
type: 'POST',
url: 'serverlink/findobject',
data: {
findChannel: $streamerName,
checkOnline: true
},
success: function(response)
{
$streamData = JSON.parse(response);
$('#streamPreview').remove();
// $('#findPanelToolbar').before($streamData.streamerView);
console.log($streamData);
}
});
});
function getProgress()
{
$.ajax({
type: 'POST',
url: 'serverlink/getprogress',
complete: getProgress,
timeout: 60000,
success: function(response)
{
$progresValue = response;
updateProgressBar($progresValue);
}
});
}
Server logic:
public function action_findobject()
{
$_SESSION['percentage'] = 0;
if(!(Input::is_ajax()))
{
$response = Response::forge();
$response->set_status(400);
return $response;
}
// Long actions //
$_SESSION['percentage'] = 10;
// Long actions //
$_SESSION['percentage'] = 45;
// Long actions //
$_SESSION['percentage'] = 100;
return $Outputdata;
}
public function action_getprogress()
{
return $_SESSION['percentage'];
}
I think you need create php script, which will execute some tot big part of process and send json with %. Also percents need to be stored in session. In browser you will invoke ajax till get some error or result 100%. After you got answer from server, if percents<100 -> show new percent line to customer and do the same request to server..
Not a solution so I'll wikify this but to answer the question, "is this not possible using php sessions?"... looks like a no - or at least not in the code's current form. You would have to delegate the resource-intensive operation to another process somehow as the following simple test suggests that the first operation is blocking.
<?php // sleep.php
session_start();
$_SESSION['foo'] = gmdate('r');
sleep(10);
<?php // test.php
session_start();
echo !isset($_SESSION['foo'])
? 'session not set'
: $_SESSION['foo'];
Test:
Browse /sleep.php which sets some value in the session then waits for 10 seconds (arbitrary) to mimic some exhaustive program/execution. Open a new tab inside of the 10 second delay and browse /test.php.
Expected Result:
/test.php immediately returns the date that was set by /sleep.php
Actual Result:
/test.php request hung/waited until /sleep.php request had finished.
I managed to solve this problem using caching in a file, dont know how optimal that is, but thanks to everyone for your suggestions!
Related
I have a timing problem with an ASP.NET core 5 system I'm working on. My page shows a DataTable with id='outsideDataTable', and when an item is selected a modal bootstrap dialog is shown. The submit button invokes method submitModal() which does this:
$.ajax({
type: 'POST',
url: '/api/Submit',
dataType: 'json',
statusCode: {
200: SubmitDone()
},
error: 'SubmitError',
data: $('#ModalForm').serialize()
});
The /api/Submit function calls the server's Submit function which does an update to the database. None of the C# code uses async coding. The database interface is NPoco. At the end of the update the function calls Ok() which I believe returns the status 200 to the ajax call.
[HttpPost("api/[action]")]
public IActionResult Submit(
int recordId,
... other formdata ...)
{
if (recordId == 0)
{
var sr = new Record() { ... fill with form data ... };
db.Insert(sr);
}
else
{
var sr = db.Single("select * from Records where recordId=#0", recordId);
if (sr == null)
return BadRequest($"Couldn't find record with ID={recordId}");
... update sr with form data ...
db.Update(sr);
}
return Ok();
}
The OK() function returns status of 200 back to the client, which should now execute the js SubmitDone() function.
function SubmitDone() {
$('#ModalDlg').modal('hide');
$('#outsideDataTable').DataTable().draw();
}
The problem is that when the outsideDataTable is redrawn from within the SubmitDone function, it will retrieve the data, which does not yet include the changes put into the database by the submit action routine. Why is that? In my opinion the database should have done its thing by the time the status 200 is returned to the ajax call, ergo when the redraw happens the database should have the new data.
As a matter of fact, in fiddler I see that the list load from the redraw happens before the ajax to the submit function.
I have not isolated this into working code I can share, but can do so if needed - unless someone knows what I'm doing wrong.
When you assign the SubmitDone function to the statusCode.200 callback you shouldn't use parentheses because this is making the function execute immediately. Instead, it should be like this:
$.ajax({
type: 'POST',
url: '/api/Submit',
dataType: 'json',
statusCode: {
200: SubmitDone
},
error: 'SubmitError',
data: $('#ModalForm').serialize()
});
Good morning,
I have script that updates voluminous data (for exemple 3000Lines) and I have to show to user progress of db updates on progress bar or just the number of lines affected.
I'm working on PHP codeigniter and AJAX
I had an idea to use session codeigniter to store modified variable (incrementation) on the session value on each Loop and call function that give me the session variable as JSON array, but the problem is that the session wouldn't change itself after first update (for exemple: starting with 0 and modified to 20, after that all process on 20)
I don't know how to get better solution to do it. If you can help me it will be really cool.
Thank's to all
PHP won't output anything until the script has fully completed, but you can change that:
ob_implicit_flush(true);
for ($i = 0; $i < ob_get_level(); $i++) {
ob_end_clean();
}
Put this in your PHP script before you start processing your data. As you process parts of your data, output something to tell the AJAX request the progress; for example:
PHP:
$completed_updates = 0;
$last_echoed_progress = 0;
$progress_echo_interval_seconds = 2;
while ($completed_updates < $amount_of_db_updates_to_do) {
do_db_update();
$completed_updates++;
if ($last_echoed_progress + $progress_echo_interval_seconds < time()) {
echo ($completed_updates / $amount_of_db_updates_to_do) * 100;
$last_echoed_progress = time();
}
}
jQuery's .ajax also (by default) won't call the success function with the data until all the data has been received (i.e. script ended), so create a custom XHR object with an event listener that receives the data while the script is still running:
JS:
var last_response_length = 0;
$.ajax({
... // All your other settings
xhr: function() {
var xhr = new XMLHttpRequest(); // Create a custom XHR object
xhr.onprogress = function(data) {
var response = data.currentTarget.response, // Get the output
progress = response.slice(last_response_length) | 0; // Remove old output
$( '#progress-bar' ).val(progress); // Update the progress bar
last_response_length = response.length; // Track where the old data is (so they can be removed when new data is received)
};
return xhr; // IMPORTANT! Return the custom XHR for .ajax to use
},
success: function(response) {
$( '#progress-bar' ).val(100); // All done!
}
});
Obviously modify the code to suit your needs, and experiment a little. Keep in mind that PHP has an execution time limit of 30 seconds by default, so you may need to change this inside your script:
set_time_limit(0);
This allows your script (and only that one) to run without time limits. Put it at the very top. Use caution!
I have a Javascript function that pulls in the users latitude/longitude and stores it in an array for later use. What I'm trying to do is take the users latitude/longitude and run a distance comparison to several other latitude/longitudes which are stored in a database. What I'm trying to do, and I could be thinking about this all wrong, is make a call with AJAX within that Javascript, to a specific function within a PHP file (the function pulls just the latitude/longitude of each related store from the database). Normally, this should be easy, but there are multiple functions within the PHP file so I'm wondering if this can even be accomplished this way.
Thank you in advance for any help you can provide. I'm still new to all of this so your patience is appreciated.
This is the code I have so far (I'm brand new to AJAX so I don't have any AJAX code written yet):
function userPosition() {
navigator.geolocation.getCurrentPosition(function(position) {
var lat = position.coords.latitude;
var lng = position.coords.longitude;
currentPos.push(lat, lng);
}, function(error) {
alert('Error occurred. Error code: ' + error.code);
// error.code can be:
// 0: unknown error
// 1: permission denied
// 2: position unavailable (error response from location provider)
// 3: timed out
});
};
Here's the code within the PHP file:
public function get_closest_location() {
$addresses = array();
$i = 0;
//Get primary address
$addresses[$i]['lat'] = $this->dealer_info['lat_1'];
$addresses[$i]['lng'] = $this->dealer_info['lng_1'];
//Get Dealer Addresses
global $wpdb;
$results = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->gdp_dealers_addresses WHERE dealerId = %d", $this->dealer_info['dealer_id'] ), ARRAY_A );
foreach($results as $res){
$i++;
$addresses[$i]['lat'] = $res['lat'];
$addresses[$i]['lng'] = $res['lng'];
}
return $addresses;
}
The answer is Yes and No, so the solution is not totally straight forward
As you can only get AJAX to directly run a PHP script and not a function inside it, all you need to do is add some information to the POST data that you send to the PHP script to tell it what function within your PHP library you want to run.
So you add something like this to the posted variables
var params = {.........};
$.ajax({
method: "POST",
url: "some.php",
data: { toRun: 'userPosition', anyData: params }
})
.done(function( msg ) {
alert( msg );
});
Then in your PHP that is the first thing you test for
<?php
// check for existance of all required post variables
switch ($POST['toRun']) {
case : 'userPosition'
// get any other parameters out of POST array you may need
$params = array(.....);
userPosition();
break;
case : 'otherFunction'
...
...
default :
echo 'Huston we have a problem';
This is a basic outline and you will of course have to add some more code to look after passing back data, but this is the basic outline
}
Php essentially runs from top to bottom. Calling the file ftom the browser does just that.
If the file contains function definitions, but no calling code, nothing will be run.
To handle your problem, you need to:
Identify the function to be called
Check it is an allowed function, to avoid malichious code injection
Call the function
To do that, you can send the required function as a get parameter, check it against a whitelist, and call it:
//example.php
function somefunc(){}
function anotherfunc(){}
function privatefunc(){}
function onLoad(){
$func = isset($_GET['func']) ? $_GET['func'] : false;
$allowed = ['somefunc','anotherfunc'];
if(in_array($func, $allowed){
call_user_func($func);
}
}
//call onload function when script is executed
onLoad();
To call a function you would use the correct query string in your ajax request, eg /example.php?func=somefunc
I would recommend you pass a GET parameter to the php script. This would look as follows:
javascript:
$.post( "script.php?action=userPosition", { lat: "2.0123123", long: "2.0319239123" })
.done(function( data ) {
alert( "Data Loaded: " + data );
});
append this to your php file:
if (isset($_GET["action"]) && $_GET["action"] == "userPosition") {
echo get_closest_location($_POST["lat"], $_POST["long"]);
exit;
}
you would need to modify the arguments of the php function obviously, but then this would be all it takes.
I have a website, where users can get inbox messages and notifications while they are on the website. (Like on facebook, you see (1) at the begining of the tile as you have notification)
Currently I have an ajax request which grabs the data the title has to show. It works liek charm but the issue is that this file is called every 10 seconds. If user has 10 page tabs though, this file is called 10x10=100 times.. if my site has thousand users, you understand how much load it would generate.
I though of running the javascript on active tab only but how can I update the title of all opened tabs of my website? Any other suggestion?
Here is my code
var oldtitle=$(document).attr("title");
var checker=function(){
$.ajax({
url : 'live_title.php',
type : 'POST',
success : function(data) {
... code ....
... code ....
... code ....
if (sum>0) {
$(document).attr("title", "("+sum+") "+oldtitle);
}
}
});
}
setInterval(checker,20000);
checker();
A cache mechanism seems the right way to go.
First idea: use HTTP caching
Be sure to add a parameter as a query string with the current timestamp rounded to the previous 10th of second.
Be sure your web server sends the correct header for the HTTP cache to work. It's best with a GET request.
Example:
$.ajax({
url : 'live_title.php',
type : 'GET',
success : function(data) {
// code
},
data: {t: Math.floor((+new Date())/10000)}
}
// we send a request similar to live_title.php?t=142608488
Second idea: use window.localStorage as a secondary local cache.
Additionnaly to the first idea:
var getCache = function(t) {
if (window.localStorage) {
var liveTitle = localStorage.getItem('liveTitle') || {};
return liveTitle[t] || null;
}
};
var setCache = function(t, data) {
if (window.localStorage) {
window.localStorage.setItem('liveTitle', {t:data});
}
}
var run = function() {
var t = Math.floor((+new Date())/10000);
var cache = getCache(t);
var success = function(data) {
/*code*/
};
if (cache) {
success(cache);
}
else {
$.ajax({
url : 'live_title.php',
type : 'GET',
success : function(data) {
setCache(t, data);
success(data);
},
data: {t: t}
}
}
}
I don't think you can do what you want easily.
Moreover to optimize that, I would recommend to use cache :
One time a tab calls the method which count the messages, do the query and cache the result to a simple file or in memory
during the next 5 minutes, each time a tab calls the method, use the cache and do not query the database
when the 5 minutes are passed, do again a query, cache it and so on.
Like this, on 100 calls, you have only 1 big request, others are like requesting a js or img files
I don't how to ask this question but if their are duplicates send me that. Their are several .php files i have made
content.php, show.php and showFilteredResult.php .
content.php sends the start date and end date to the show.php and it returns the the orderIds which are of that date
$(document).ready(function () {
var srt = $("#cal1Date1").val();
var end = $("#cal1Date2").val();
$.ajax({
url: "http://localhost/show.php",
data: {
srt: srt,
end: end
},
type: "POST",
dataType: "json",
complete: function (response) {
$rtndata = response.responseText;
var dat1a = jQuery.parseJSON($rtndata);
var result = dat1a.OrderID;
console.log(result[0]); // send this result
}
});
});
now I want to send this $result with orderids to showFilteredResult.php where then i can make tables etc.
I'd skip the AJAX and just use request parameters (GET or POST).
cal1Date1 and cal1Date2 are input fields I assume. Wrap them in a form and post the values to a PHP form handler that could handle the lookup and display. No need for the AJAX middle-man here.
Just make a similar Ajax request to showFilteredResult.php I would have them in a separate function.
function showFilteredResult($result){
$.ajax({
url:"http://localhost/showFilteredResult.php",
data: {
result:$result
},
type:"POST",
dataType: "json",
complete:function(response){
$rtndata=response.responseText;
var dat1a=jQuery.parseJSON($rtndata);
var result=dat1a.OrderID;
console.log(result[0]);// do something with the data returned from showFilteredResult.php
}
});
}
and from the request that you have just call that funciton like
... $rtndata=response.responseText;
var dat1a=jQuery.parseJSON($rtndata);
var result=dat1a.OrderID;
console.log(result[0]);// send this result
showFilteredResult(result[0]);
}
});
Instead making another request to server , you have another option to do that. Let's say you get orderId from show.php before sending back , right ? Then you can use this orderId to do what u want such as query which u have written in showFilteredResult.php . then return back to client for final result . In that way you can eliminate the unnecessary http request.