I would like to thanks you for helping me.
I am quite new to programming, so I might just be missing some important(s) point(s) in spite of my numerous researchs, but here is my issue.
I have a html file with a button.
<span class="input-group-addon btn" id="go">Go</span>
On click, I send a post request to a php file.
$('#go').click(function(event) {
event.preventDefault();
$.post('myphpfile.php',({var1: anyval1, var2: anyval2}));
}
And then myphpfile starts a long treatment loop.
if (isset($_POST['var1'])&&($_POST['var2']!=="")) {
$var1 = htmlspecialchars($_POST['var1']);
$var2= htmlspecialchars($_POST['var2']);
$myarray = create_some_array($var1,$var1);
foreach ($myarray as $key=>$value){
do_sql_stuff($value);
}
}
Now the thing is, I would love to know what is the progress since I sent the request. I've been able to do since by writing the $key to a file, and then reading it with javascript.
myphpfile.php
file_put_contents('somefile.txt',$key.'/'.count($myarray));
myjsfile.js
$.ajax({
url : "somefile.txt",
dataType: "text",
success : function (data) {
console.log(data);
}
});
But if I want to have multiple users running the function, I will have to create as many files, which doesn't seem appropriate.
So I've heard about Server-Sent event, which allow the server to push data to the client browser, and tried to adapt my code.
myphpfile.php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
$prg = 0;
echo "data: ".$prg."\n\n";
myjsfile.js
var jsonStream = new EventSource('myphpfile.php');
jsonStream.onmessage = function (e) {
console.log(e);
};
This works, but if I put the echo within the loop, the event never get triggered, while outside, it is always triggered but with the wrong value (based on the console.log outputs).
So what am I missing ?
Why is the event always triggered while the function isn't running ?
I still feel like the javascript is pulling the data, and the php not pushing it like I intend to, which lead the data to be innacurate.
Does it have anything to do with the file being a POST target ?
Should i create another file running a while loop with a global variable (which seems a little bit excessive just to get one php variable) ?
Just so there is no misunderstanding, here are the actual 2 files :
myphpfile.php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
if (isset($_POST['var1'])&&($_POST['var2']!=="")) {
$var1 = htmlspecialchars($_POST['var1']);
$var2= htmlspecialchars($_POST['var2']);
$myarray = create_some_array($var1,$var1);
foreach ($myarray as $key=>$value){
do_sql_stuff($value);
echo "data: ".$key."\n\n";
ob_flush();
flush();
}
}
myjsfile.js
$(document).ready(function(){
$('#go').click(function(event) {
event.preventDefault();
$.post('myphpfile.php',({var1: anyval1, var2: anyval2}));
}
}
var jsonStream = new EventSource('myphpfile.php');
jsonStream.onmessage = function (e) {
console.log(e);
};
If anyone has any idea, that would be great !*
Thanks for reading.
PS : Sorry for any spelling mistake, I am french :D
Related
I want to make a progress bar on my website, which tracks execution of a PHP script.
The PHP script makes a bunch of connections with Google API and stores the data it receives in the database. Sometimes the process can take a minute.
The PHP script is located in ajax/integrations-ajax.php file and launched by GET AJAX request sent, if on the website to click #link button. Below is jQuery code for the request:
$('#link').on('click', function () {
var interval = setInterval(trackStatus, 1000);
$.getJSON('ajax/integrations-ajax.php', {action: 'link'}).done(function (json) {
if (json.result == true) {
showMessage('The account is successfully linked.', 'success');
} else {
showMessage('There is an error happened.', 'danger');
}
})
});
This #link button, also sets interval which fires trackStatus function each second:
function trackStatus() {
$.getJSON('ajax/status-ajax.php', {
action: 'status'
}).done(function (json) {
console.log(json.status);
});
}
As you can see, trackStatus function sends GET AJAX requests to ajax/status-ajax.php file and should show status in browser console every second.
To implement tracking ability on the server I made the PHP script in ajax/integrations-ajax.php file to store status in the database. Its code you can see below:
<?php
if(!is_ajax_request()) { exit; }
$action = isset($_GET['action']) ? (string) $_GET['action'] : '';
if ($action == 'link') {
set_status_in_database(0);
// some execution code;
set_status_in_database(1);
// some execution code;
set_status_in_database(2);
// some execution code;
set_status_in_database(3);
// some execution code;
echo json_encode(['result' => true ]);
}
And created another PHP file axax/status-ajax.php which can recover the status from the database:
<?php
if(!is_ajax_request()) { exit; }
$action = isset($_GET['action']) ? (string) $_GET['action'] : '';
if ($action == 'status') {
$return['result'] = get_status_from_database();
echo json_encode($return);
}
But the requests appear not to be working simultaneously. I can't receive responses for trackStatus function until the response on completion ajax/integrations-ajax.php script isn't received.
I made a profiling record in browser, which show that:
So, is there a possibility to execute requests simultaneously? Or to implement the tracking ability I need to rethink the whole approach?
Thanks in advance for help!
Update
Thank you all for your advice! And especially to #Keith, because his solution is the easiest and works. I have put session_write_close() function in the beginning for the script and everything works:
<?php
if(!is_ajax_request()) { exit; }
$action = isset($_GET['action']) ? (string) $_GET['action'] : '';
if ($action == 'link') {
session_write_close();
set_status_in_database(0);
// some execution code;
set_status_in_database(1);
// some execution code;
set_status_in_database(2);
// some execution code;
set_status_in_database(3);
// some execution code;
echo json_encode(['result' => true ]);
}
Here you can see profiling record from a browser:
While PHP can handle concurrent requests without issue, one area that does get serialized is the Session, basically PHP during a request will place an exclusive lock on the SESSION, for that user. IOW: While this lock is on, other requests from the same user will have to wait. This is normally not an issue, but if you have long running requests it will block other requests, like AJax requests etc.
As a default PHP will write session data at then end off the request,. But if you are sure you no longer need to write any session data, calling session_write_close will release the lock much sooner.
More info here -> http://php.net/manual/en/function.session-write-close.php
Would advise trying EventSource. Here is an example.
PHP
<?php
header('Content-Type: text/event-stream');
// recommended to prevent caching of event data.
header('Cache-Control: no-cache');
function send_message($id, $message, $progress) {
$d = array('message' => $message , 'progress' => $progress);
echo "id: $id" . PHP_EOL;
echo "data: " . json_encode($d) . PHP_EOL;
echo PHP_EOL;
ob_flush();
flush();
}
for($i=0; $i<4; $i++){
set_status_in_database($i);
// some execution code;
send_message($i, "set status in database " . $i + 1 . " of 3' , $i*4);
sleep(1);
}
send_message('CLOSE', 'Process complete');
?>
JavaScript
var es;
function startTask() {
es = new eventSource('ajax/status-ajax.php');
es.addEventListener('message', function(e) {
var result = JSON.parse(e.data);
console.log(result.message);
if(e.lastEventId == 'CLOSE') {
console.log('Received CLOSE closing');
es.close();
showMessage('The account is successfully linked.', 'success');
} else {
$('.progress').css("width", result.progress + '%');
}
});
es.addEventListener('error', function(e) {
console.log('Error occurred', e);
es.close();
});
}
function stopTask() {
es.close();
console.log('Interrupted');
}
$('#link').on('click', function(e) {
e.preventDefault();
startTask($(this));
});
Reference:
Show Progress Report for Long-running PHP Scripts
Hope that is useful for you.
Both php logic and JavaScript syntax seem to be fine; however, with the minimal amount of php code example it is assumed that it’s resource heavy. MySQL might be busy, which is why get status may wait for MySQL.
I have gone around such a problem by making the update status written to a file instead of competing for database resources.
Since you consider using a different approach, let me recommend GraphQL as a thin layer / api above your database.
There are quite a few Php-solutions out there, for example Siler. Look for one that has subscriptions (not all do), as this would be the feature you are looking for. Subscriptions are used to create a websocket (stream between your Php and Javascript), reducing all status-related communication to one call.
Yes, this may be "shooting cannons at birds", but maybe you have other things flying around, then it might be worth considering. There is a fantastic document to familiarize with the intriguing concept. You'd be able to reuse most of your database-related Php within the resolver functions.
I want to form a string in my php server code as xml, and then send it to javascript so that ajax.responseXML can navigate through it and do things with the data. I haven't been able to find exactly what I need to accomplish this and have tried a few different methods. Here's the most recent thing I've tried.
<?php
header("Content-type: text/xml");
$xmlstring = "<?xml version'1.0' encoding='UTF-8'>";
$xmlstring = $xmlstring . "<book name='$name' author='$author'>";
foreach($rankings as $entry)
{
$xmlstring = $xmlstring . "<rank>$entry</rank>";
}
echo $xmlstring;
?>
I know the data is getting there because if I echo it as a string and open it directly, the numbers I need are getting printed. I'm using Ajax.Request to open the php file with certain parameters, and when it reaches the onSuccess function, ajax.responseXML is null. This is my first time dealing with xml so I could be doing something stupid.
function that makes the call:
function findRankings(author, name)
{
new Ajax.Request("server_code.php",
{
method: "get",
paramters: {"type": "rank", "name": name, "author": author},
onSuccess: makeGraph,
onFailure: ajaxFailed
});
}
function makeGraph(ajax)
{
alert(ajax.responseXML); // testing that it made it
.....// do stuff with the response
}
EDIT: I added the header and made it echo just the string. I also added the ajax functions. I keep getting null though. :(
As Dustin said, you need to echo $xmlstring; instead and add header('Content-Type: text/xml');
But you also have a couple of errors in your XML declaration. You're missing a = and a ?:
$xmlstring = "<?xml version='1.0' encoding='UTF-8'?>";
I'd recommend using an XML validator in future.
You used simplexml_load_string, which converts your XML string to an object.
Just echo your $xmlstring
For clean coding you should insert header('Content-Type: text/xml'); as #Twisty mentioned.
I am not sure if this is the best way to do it, but I have a button that when pressed it call a onClick JS function and it passed two parameters. I want to save those two parameters on a php session, then load another page and use those values.
So, I know that if I use something like this on PAGE !:
<?php
session_start();
$message1 = "A message";
$message2 = "Another message";
$_SESSION['routineName'] = $message1;
$_SESSION['dayName'] = $message2;
?>
I can go to PAGE 2, and by using $_SESSION['routineName'] I can use that info.
So, on PAGE 1 I have that code inside the function that is called with my onClick:
function trackIt(routine, dayName)
{
<?php
session_start();
$message1 = "A message";
$message2 = "Another message";
$_SESSION['routineName'] = $message1;
$_SESSION['dayName'] = $message2;
?>
}
I tried things like:
function trackIt(routine, dayName)
{
<?php
session_start();
$_SESSION['routineName'] = ?> routine; <?php
$_SESSION['dayName'] = $message2;
?>
}
and others, but nothing works.
And this is how I am calling the onClick (trackIt) function:
echo('<td colspan="3" style="background-color:#005673; text-align:right; padding: 4px 0px;">
<button class="btnTrack" onClick="trackIt(\'' . $name . '\' , \'' . $nameday1 . '\')" >Track It!</button></td>');
What I want to do is to save both, routine and dayName, into the session.
Is it possible to save JS variables/parameters into PHP Session?
PS: I am using Wordpress.
Thanks!
The PHP code you put in your files is not executed at Javascript run time, it is executed even before the page gets sent to the client. So you can't access $_SESSION from anywhere within your content, you need to do that from Wordpress's code. Usually this is done via a plugin.
You need to pass your Javascript variables to a server side PHP. As #Grasshopper said, the best (or at least most maintainable way) is through AJAX:
// This is your JAVASCRIPT trackit function
function trackIt(routine, day) {
$.post(
'/wp-setvar.php',
{
routine : routine,
day : day
}, // You can add as many variables as you want (well, within reason)
function success(data) {
// Here we should receive, given the code below, an object
// such that data.result is a string saying "OK".
// Just in case you need to get back something from the server PHP.
// Otherwise just leave this function out.
}
);
};
On the server, you need to create a specific file to accept the incoming variables (it would be best if you did this from a plugin, in order not to add files outside the installation: such practices are frowned upon by security scanners such as WordFence). This here below is a butcher's solution.
<?php /** This is wp-setvar.php */
/** Set up WordPress environment, just in case */
require_once( dirname( __FILE__ ) . '/wp-load.php' );
session_id() || session_start();
nocache_headers();
// DO NOT, FOR ANY REASON, ACCESS DIRECTLY $_SESSION
// ONLY USE A VARIABLE WITHIN $_SESSION (here, "ajjx")
// OTHERWISE THIS MAY ALLOW ANYONE TO TAKE CONTROL OF YOUR INSTALLATION.
$_SESSION['ajjx'] = $_POST;
Header('Content-Type: application/json;charset=utf8');
die(json_encode(array(
'result' => 'OK', // This in case you want to return something to the caller
)));
Now whenever you need the session-saved variable, e.g. "routine", you put
<?php
...
$value = '';
if (array_key_exists('ajjx', $_SESSION)) {
if (array_key_exists('routine', $_SESSION['ajjx']) {
$value = $_SESSION['ajjx']['routine'];
}
}
Or you can define a function in your plugin,
function ajjx($varname, $default = '') {
if (array_key_exists('ajjx', $_SESSION)) {
if (array_key_exists($varname, $_SESSION['ajjx']) {
return $_SESSION['ajjx'][$varname];
}
}
return $default;
}
Then you just:
<?php print ajjx('routine', 'none!'); ?><!-- will print routine, or "none!" -->
or
<?php print ajjx('routine'); ?><!-- will print nothing if routine isn't defined -->
An even more butcherful solution is to add the function definition above within wp-config.php itself. Then it will be available everywhere in Wordpress. Provided you have access to wp-config.php. Also, backup wp-config first and use a full FTP client to do it; do not use a Wordpress plugin to edit it, since if wp-config crashes, the plugin may crash too... and you'll find yourself in a my-can-opener-is-locked-within-a-can situation.
If you don't feel comfortable with some of the above, it's best if you do nothing. Or practice first on an expendable Wordpress installation that you can reinstall easily.
i'm trying to refresh page every 3 second, the url page change with $_GET variable.
i'm trying to save $_GET var into session and cookie, but get error header has already sent.
how to change url after page reload ?
here my script :
Index.php
<?php
session_start();
$skill =$_SESSION['skill'];
?>
<script type="text/javascript">
var auto_refresh = setInterval(function () {
$('#src2').load('monitor.php?skill=<?php echo $skill;?>').fadeIn("slow");
}, 3000);
</script>
monitor.php
<?php
include "conn.php";
session_start();
$_SESSION['skill'] = $_GET['skill'];
if ($_SESSION['skill']=='')
{
$a ="bro";
$_SESSION['skill']=4;}
elseif ($_SESSION['skill']==4){
$a = "yo";
$_SESSION['skill']='5';
}
elseif ($_SESSION['skill']==5){
$a = "soo";
}
?>
First off, "headers already sent" means that whichever file is triggering that error (read the rest of the error message) has some output. The most common culprit is a space at the start of the file, before the <?php tag, but check for echo and other output keywords. Headers (including setting cookies) must be sent before any output.
From here on, this answer covers how you can implement the "refresh the page" part of the question. The code you provided doesn't really show how you do it right now, so this is all just how I'd recommend going about it.
Secondly, for refreshing the page, you will need to echo something at the end of monitor.php which your JS checks for. The easy way is to just echo a JS refresh:
echo '<script>window.location.reload();</script>';
but it's better to output some JSON which your index.php then checks for:
// monitor.php
echo json_encode(array('reload' => true));
// index.php
$('#src2').load('monitor.php?skill=<?php echo $skill;?>', function(response) {
if (response.reload) window.location.reload();
}).fadeIn('slow');
One last note: you may find that response is just plain text inside the JS callback function - you may need to do this:
// index.php
$('#src2').load('monitor.php?skill=<?php echo $skill;?>', function(response) {
response = $.parseJSON( response ); // convert response to a JS object
if (response.reload) window.location.reload();
}).fadeIn('slow');
try putting
ob_start()
before
session_start()
on each page. This will solve your problem.
Without looking at the code where you are setting the session, I do think your problem is there. You need to start the session before sending any data out to the browser.
Take a look at: http://php.net/session_start
EDIT:
Sorry, a bit quick, could it be that you send some data to the browser in the 'conn.php' file? Like a new line at the end of the file?
Sorry if this is still another thread on the subject but I am struggling since hours but could not find the solution.
I am trying to get data from a Mysql database, create a JSON with php, then parse this JSON in javascript.
Here is my json.php
<?php
$link = mysql_pconnect("localhost", "root", "") or die("Could not connect". mysql_error());
mysql_select_db("people") or die("Could not select database");
$arr = array();
$rs = mysql_query("SELECT * FROM nom");
while($obj = mysql_fetch_object($rs)) {
$arr[] = $obj;
}
echo '{"users":',json_encode($arr),'}';
/*
//The json object is :
{"users":[{"id":"1","prenom":"Alain","age":"23"},{"id":"2","prenom":"Bruno","age":"24"}]}
*/
?>
Then I try to parse it into java
<div id="placeholder6"></div>
<script src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script>
$.getJSON('http://localhost/json.php', function(data) {
var output="<ul>";
for (var i in data.users) {
output+="<li>" + data.users[i].id + " " + data.users[i].prenom + "--" + data.users[i].age+"</li>";
}
output+="</ul>";
document.getElementById("placeholder6").innerHTML=output;
});
</script>
when I replace localhost/json.php by the result in a file data.json, it works, when I open localhost/json.php with firefox, I can see the JSON table...so I do not know why it does not work with localhost/json.php.
Is my php code or javascript code wrong ?
Thanks in advance for your help !
Try this method
var users= data.users;
$.each(users,function(index,users){
console.log(users.prenom); /// and users.id etc
})
Try This in php
while($obj = mysql_fetch_object($rs)) {
$arr[] = $obj;
}
$return = new stdClass();
$return ->users = $arr;
echo json_encode($return);
I think your web application server (like Apache or nginx) sends Content-Type: text/html by default or something of that sort for your json.php file. On the other hand, it looks like $.getJSON method requires a application/json content type field.
Try adding:
header("Content-Type: application/json");
to the top of the json.php file.
Edit - additional info:
I couldn't find in the original documentation of the $.getJSON method whether it, in fact, requires the specific Content-Type so I looked into the source code:
https://github.com/jquery/jquery/blob/1.7.1/src/ajax.js#L294
Here is the line of source code for jQuery 1.7.1 (which is the version you said that you use, I hope) for getJSON and as you can see, it calls jQuery.get with the last argument set to "json".
In turn, the jQuery.get documentation reveals that this argument means:
The type of data expected from the server. Default: Intelligent Guess (xml, json, script, or html).
from: http://api.jquery.com/jQuery.get/
Thus, when you call $.getJSON("/url/to/file", ...) that first argument is expected to be a JSON. If you add the PHP code from the top of my answer, your web application server will mask the output of the php file as a JSON.