Realtime Ouput while PHP Function is Executing - php

My problem is that I need a PHP script to continously provide ouput at certein points of it's execution. I have workng AJAX to fetch the html but it only echos once the script is complete. Here is an example:
<?php
class test {
function test() {
echo '1';
sleep(20);
echo '2'
sleep(5);
}
}
I need some way to have the echo's actually displayed in the browser even though the function is still continuing. I have tried using global variables and session variables to no avail.
Thanks for the help!

I've seen many questions where people are trying to do this type of thing, but as far as I know it really isn't possible to do it the way you're trying to do it using only PHP and AJAX. In order for this to work using just AJAX rather than websockets or some other approach, you can break your script into separate pieces at the points where it needs to provide output, and provide the output as responses to separate AJAX requests. Here is a basic example of what I mean. The script on your page can start the process and makes repeated calls to step through the process until it's complete.
<button id="begin_process">Start</button>
<script type="text/javascript">
function step(step_number) {
$.get('test.php', {'step_number': step_number}, function(response){
console.log(response.message);
if (response.next_step) {
step(response.next_step);
}
}, 'json');
}
$(document).ready(function(){
$('#begin_process').click(function(){
console.log('go!');
step(1);
});
});
</script>
test.php:
<?php
class Test {
function step($step_number) {
switch ($step_number) {
case 1:
return array('next_step' => 2, 'message' => 'step 1 complete');
case 2:
sleep(20);
return array('next_step' => 3, 'message' => 'step 2 complete');
case 3:
sleep(5);
return array('message' => 'finished');
}
}
}
$test = new Test();
echo json_encode($test->step($_GET['step_number']));

Related

Ajax : How/ Is it possible to parse a '.html(response)'

so am making this chat, and am trying to add functionalities.
SO far, I have here is what i achieved.
I have a function that displays messages.
function displayMessages()
{
$.post('core/chat.php?action=read',function(response)
{
$('.message_display').html(response);
});
}
this function is called every second
setInterval(function(){displayMessages();},1000);
the content of the 'reponse' is generated in php.
foreach($messages as $chat_msg)
{
echo '<span style="color:#'.$chat_msg['color'].';">['.$chat_msg['user_name'].']:'.$chat_msg['txt'].' </span><br>';
}
so i build a function that play sound : playsound(file).
I initially wanted to attach it to the function displayMessages()...
function displayMessages()
{
$.post('core/chat.php?action=read',function(response)
{
$('.message_display').html(response);
});
playSound ("send_message");
}
...but of course, that plays the sound at each refresh, having a new message or not.
So,to fix it, i thought of adding on the php sidee, a code that triggers the sounds if a new message was posted: "ex:
echo $playsoundtrigger="playsound";
but then i have no clue, on what to do next.
how can i parse response, so the ajax break down the html on 1 side and the $playsoundtrigger on the other?
something along the line i would have approach like this if it was php:
parse_str("reponse+$triger=true");
if ($triger){
playsound();
}
I look for a parse function in ajax, but all reference i could find was to parse json...
any solution?
or hint on a logic to address my problem?
Note: I looked, and find that ajax, could tell me if the content has changed, based on his side, but I do not want to go this way, as I would like in the long run, to adapt the sounds on the message :)
thank you
Polling your server on every second!!! Hm... you are essentially DDOS ing your own server. I think web sockets are what you need. But don’t know much about it.
As for your answer, you could actually use json, then build the nodes from browser.
Eg:
$data = [];
foreach ($messages as $chat_msg) {
$data[] = [
'color' => $chat_msg['color'],
'user_name' => $chat_msg['user_name'],
'txt' => $chat_msg['txt']
];
}
echo json_encode([
'trigger' => 1
'data' => $data
]);
and in your js
function displayMessages()
{
$.post(
'core/chat.php?action=read',
{},
function(res) {
var html = '';
res.data.foreach(function(msg) {
html += '<span style="color:#' + msg.color + ';">[' + msg.user_name + ']:' + msg.txt + '</span><br>';
}
$('.message_display').html(html);
if(res.trigger) {
playSound ("send_message");
}
},
'json'
);
}

PHP calling function with parameters by clicking on HTML div

I am trying to make a delete button which I'll be able to delete some user from my database but main thing how to call PHP function with clicking on some div etc..
<div class="cross" onclick='<?php deleteUser("Nickname")?>'>X</div>
<?php
function deleteUser($username) {
//... code
}
?>
Html can't directly call php, it can do a separate call to load the same page, with the action.
<?php
function deleteUser($username){}
if($_GET['action'] == "delete")
{
deleteUser($_GET['username']);
}
?>
<a class="cross" href='?action=delete&username=NickName'>X</a>
The reason for this is because PHP runs on the server, BEFORE anything is sent to the browser. So it requires another page load to run the function by clicking something. It is possible to use javascript and AJAX calls to send a call to a php script without reloading the main page. Just look into Jquery's post or ajax features.
You cannot call a PHP function that resides on the server by just clicking on a div that exists on the client browser.
You need to trigger a Javascript event (using e.g. jQuery), that will call a function on the server (e.g. through AJAX), that after checking the parameters are correct and the user has the right of calling it will do what you seek.
There are ready-made frameworks that would allow you to do that.
Otherwise (after including jQuery in your HTML page) you can do something like,
<div class="cross" id="deleteUserButton" data-user="nickname">X</div>
<script type="text/javascript">
$('#deleteUserButton').on('click', function() {
let nick = $(this).attr('data-user');
$.post('/services/delete.php',
{
cmd: 'delete',
user: nick
}).then( reply => {
if (reply.status === 'OK') {
alert("User deleted");
}
});
<?php
$cmd = $_POST['cmd'];
switch($cmd) {
case 'delete':
$user = $_POST['user'];
if (deleteUser($user)) {
$reply = [ 'status' => 'OK' ];
} else {
$reply = [ 'status' => 'failure', 'message' => 'Doh!' ];
}
break;
...
header('Content-Type: application/json;charset=UTF-8');
print json_encode($reply);
exit();

Executing PHP function from JSON

I am trying some things with JSON and PHP and there is something that I can't find a way to do, though I'm not 100% sure there is one. But because it looks like a nice option (If possible) I decided to ask here.
I have these examples from jquery offical site. There are two files, the first one is index.php where I execute my Ajax, hete it is:
<!DOCTYPE html>
<html>
<head>
<title>Simple form sending and receiving a JSON object to/from PHP</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
var data =
{
"sales": [
{ "firstname" : "John", "lastname" : "Brown" },
{ "firstname" : "Marc", "lastname" : "Johnson" }
] // end of sales array
}
var dataString = JSON.stringify(data);
$.post('simpleformSubmi.php', { data: dataString}, showResult, "text");
});
function showResult(res)
{
$("#fullresponse").html("Full response: " +res);
}
</script>
<div id="fullresponse"></div>
</head>
<body>
Nothing complicated at all. And I have my simpleformSubmi.php which is :
<?php
$logFile = 'logFile';
$res = json_decode(stripslashes($_POST['data']), true);
error_log("result: ".$_POST['data'].", res=".json_encode($res), 3, $logFile);
error_log("\n", 3, $logFile);
//header("Content-type: text/plain");
foreach ($res as $key=>$value)
{
$str[] = $value;
}
$functionArray ="function(){ \$a = 10; echo \$a;}";
$jsStr = $str[0][1];
echo json_encode($jsStr['firstname']);
echo '<hr />';
echo json_encode($res);
echo '<hr />';
echo json_encode($functionArray);
?>
As you can see $functionArray - is in fact a string containing PHP function which I want to return back using JSON and to execute it after that. So is there any way to do that really? Now what I get in index.php afet executing the files is:
"function(){ $a = 10; echo $a;}"
Thanks
Lern
Seems like you're trying to execute a PHP function through JavaScript. Since PHP is executed server-side the only way you have to execute a PHP function in that context is to ask the server back to execute the function for you, by doing another ajax call for example.
Something like this:
index.php
$(document).ready(function(){
var data =
{
"sales": [
{ "firstname" : "John", "lastname" : "Brown" },
{ "firstname" : "Marc", "lastname" : "Johnson" }
] // end of sales array
}
var dataString = JSON.stringify(data);
//Change post() success callback function to executePHP()
$.post('simpleformSubmi.php', { data: dataString}, executePHP, "text");
//Let's define executePHP() outside post() call for clarity
function executePHP()
{
//Ask the server to execute function foo(), and get the result
$.get("example.com/somefile.php?function=foo", function(data)
{
//Success function, do whatever you want.
alert(data);
});
}
});
Then, in somefile.php
<?php
//Condition(s), if any. You could even implement this interface using REST.
//Get function to execute
if($_GET["function"] == "foo")
{
//Output function's result.
echo foo();
}
//The function you want to run
function foo()
{
//Do something
$a = 10;
return $a;
}
?>
If all went well, when JavaScript reaches the alert(data); statement you will see 10.
You cannot execute a PHP function after sending it as a response since the response is received on the client end, and PHP is a server side language.
Usually, you would just return the values. In your example, you would just return an associative array that holds the key value pair a,10.
You can return javascript functions from the PHP script and execute that on the client side using eval but eval'ing opens a pandora's box of security vulnerabilities.
You can't execute PHP code outside of a PHP server. So you can't run it in the browser.
You can, however, pass a string of JavaScript and run it through eval. Some people will tell you that's bad, but remember that eval used to be the only way to parse JSON in the first place.
In order to send back something to PHP, you must call the serverside via, p.e via GET or POST actions from a form. But, no, you cannot execute anything serverside via echo, as echo outputs to the client side. You could always use eval (http://php.net/manual/es/function.eval.php) at serverside to execute something from a POST message, but it is not recommended as it can open a great security hole.
You've returned a function (I'm assuming you meant this to be javascript), now you need to call it. This can be done by using the jQuery $.post success callback.
Try changing this..
$.post('simpleformSubmi.php', { data: dataString}, showResult, "text");
To
$.post('simpleformSubmi.php', { data: dataString}, function(data){eval(data)}, "text");
If its PHP (which it looks like) and not Javascript, then this will need to executed from the server. Being that its a server-side language 'n all.

Querying a function in functions.php?

I have a jQuery code that is going to check when the user is near the bottom of the page. That's not the problem though. This jQuery is going to send a AJAX request, giving it some details on what to load when the user is near the bottom of the page. The code looks a bit like this at the moment:
$("<div>").load('?ajax=y&offset=something', function() {
$(".empty-div").append($(this));
setTimeout(function(){ console.log('after', $(document).height()); }, 0);
setTimeout(function(){ console.log('after', $(window).height()); }, 0);
});
My main problem is that I don't know what to query or how to go about sending the information to the PHP function in functions.php. For example, I have at the moment this as my PHP function (until it's working):
function get_posts_page() {
if(isset($_GET['offset'])) {
echo"Hello!";
}
}
I'm aware the wordpress has add_action and all that but I have no idea what I would apply as an action to either function to make the PHP recieve the data the Javascript is sending. Is there a URL where all functions are parsed or something? Thanks for any help in advance. So how do I get the data from the Javascript to the PHP function in functions.php, in my theme directory?
I just made a video to show you how to use the add_action request in WordPress. You can watch it here.
Here's my javascript
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js"></script>
<script>
$('#branding img').click(function() {
$.post('<?php bloginfo('siteurl') ?>/wp-admin/admin-ajax.php', {
action: 'my_unique_action',
offset: 5
}, function(data) {
$('#content').prepend('<p>' + data + '</p>');
});
});
</script>
And the php that I used in functions.php
// Make sure it runs when the user is logged in,
// and when they are not.
add_action('wp_ajax_my_unique_action', 'get_offset');
add_action('wp_ajax_nopriv_my_unique_action', 'get_offset');
function get_offset() {
if( isset($_POST['offset']) ) {
echo 'Your ajax request was successful. Here was your offset: <strong>' . $_POST['offset'] . '</strong>';
}
die;
}
Reference: http://codex.wordpress.org/AJAX_in_Plugins
You're trying to call a PHP function from Javascript, correct?
You'll need some logic on some page which calls get_posts_page(). Either you can create a new page getPostsPage.php?offset= or you can put some logic in functions.php, something like
if(isset($_GET['function']) {
switch($_GET['function']) {
case 'get_posts_page':
get_posts_page();
}
}
However, the former approach is recommended; you don't want someone to be able to modify the function parameter and access deleteAllPosts() maliciously.
Therefore:
// getPostsPage.php
require PATH . 'functions.php';
get_posts_page(); //checks $_GET['offset']
And remember to fail gracefully (do not expose an error message) if 'offset' is not set, or whatever.

How to create Server-side Progress indicator in JavaScript?

I want to create a section in my site, where a user has a few simple update buttons.
Each of these update buttons will be going to the server, and will do a long crunching behind the scene.
While the server crunches data, I want the user to have a some kind of progress indicator, like progress bar or textual percentage.
I'm using jQuery as my JavaScript library, and CodeIgniter (PHP) as the server-side framework, if it's important...
What I was thinking about is using PHP's flush() function to report progress status to jQuery, but I'm not sure that jQuery's Ajax functions are reading the output before it's complete...
So any advice/explanation would be useful and helpful!
I'm going to give you an example using WebSync On-Demand, but the same approach would work regardless of your choice of server.
Here's what you do. First, kick off the long-running operation somehow; your user clicks the button to start this process (I'm going to assume an Ajax call, but whatever works), and you return to them some sort of identifier, we'll call that 'myId', give it a value of '1'. Whether you do that by invoking a process of some sort, etc, is up to you.
Then, in your callback from that invocation, you would write something like so:
var myId = 1; // this would be set somewhere else
client.initialize('api key');
client.connect();
client.subscribe({
channel: '/tasks/' + myId,
onReceive: function(args){
// update the progress bar
myProgressBar.update(args.data.progress);
}
});
What that'll do is subscribe your client to receive notification about updates to the task, so all that's left is to push out the updates, which you'd do in whatever process is actually running the task. That would look like (in PHP, using the SDK):
$publisher = new Publisher(
"11111111-1111-1111-1111-111111111111", // your api key again
"mydomain.com" // your domain
);
// publish data
$response = $publisher->publish(array(
array(
'channel' => '/tasks/' . $myId, //comes from somewhere
'data' => (object) array(
'progress' => '45' //45% complete
)
)
));
// success if empty (no error)
$success = empty($response);
That's it; as updates occur, they'll push out to your client in real-time.
It's pretty hard to get this right. What we've settled on for our system is a "faked" progress bar - it just animates over and over (which since it is an animated gif, you might expect!).
An alternative would be to submit to one script, and have that processing in the background (and outputting progress to a file) while making an Ajax request to another script whose only responsibility is to read that progress file and return how far through the process you are. This would work - it feels a little bit kludgy, but it would at least solve your immediate problem.
I know very little about Comet or the likes, so this is purely based on my current understanding.
3 years late, but here's a solution I came up with. Bonus: It works in IE7+
Uses:
jQuery 1.9.1
jQuery UI 1.10(quick dialog box and progress bar)
Remy's EventSource Polyfill
JSON2 polyfill
The event table:
create table updates(
evt_id int unsigned not null auto_increment,
user_id int unsigned not null,
evt_type enum('start','update','finish') not null,
evt_msg varchar(255) not null,
primary key (evt_id)
)
The HTML:
<?php
include 'libconfig.php';
session_write_close();
if(count($_POST)){
$db=db_get_connection();
$stm=new PDOStatementWrapper(db_prepare($db,'INSERT INTO bupdates VALUES (:event_id,:user_id,:type,:message)'));
if($stm->run(array(
':event_id'=>0,
':user_id'=>App::user()->getId(),
':type'=>$_POST['type'],
':message'=>$_POST['message']
)))echo 'Inserted';
return;
}
?>
<!doctype html>
<html>
<head>
<title>tester</title>
<link rel=stylesheet href="s/jquery-ui-1.10.3.custom.min.css">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="js/jquery-ui-1.10.3.custom.min.js"></script>
<script src="js/eventsource.js"></script>
<script src="js/json2.js"></script>
<script>
var MixerStatusMonitor=(function(){
var _src=null,
_handler={
onStart:function(e){
MixerStatus.setMax(parseInt(e.data));
},
onUpdate:function(e){
var data=JSON.parse(e.data);
MixerStatus.setValue(parseInt(data.progress));
MixerStatus.setStatus(data.message);
},
onFinish:function(e){
//var data=JSON.parse(e.data);
MixerStatus.hide();
_src.close();
}
};
return {
init:function(){
if(_src)_src.close();
_src=new EventSource('/daemon/updates.php?type=b');
_src.addEventListener('update',_handler.onUpdate,false);
_src.addEventListener('start',_handler.onStart,false);
_src.addEventListener('finish',_handler.onFinish,false);
MixerStatus.show();
}
};
})();
var MixerStatus=(function(){
var dialog=null,pbar=null,text=null;
return {
init:function(){
dialog=$('#buildStatus').dialog({autoOpen:false});
pbar=$('#buildStatus .progress').progressbar({value:false});
text=$('#buildStatus .text').progressbar();
},
setStatus:function(txt){
text.html(txt);
},
setMax:function(val){
pbar.progressbar('option','max',val);
},
setValue:function(val){
pbar.progressbar('option','value',val);
},
show:function(){
dialog.dialog('open');
},
hide:function(){
dialog.dialog('close');
}
};
})();
$(document).ready(function(){
MixerStatus.init();//build the UI
$('#updater').on('submit',function(){
$.ajax({
type:'post',
url:'test-updates.php',
data:$('#updater').serialize(),
beforeSend:function(){
if($('#updater select[name=type]').val()=='start'){
MixerStatusMonitor.init();
}
}
});
return false;
});
});
</script>
</head>
<body>
<p>Start event sets the max
<p>update event: {"progress":"","message":""}
<p>finish event: {"progress":"","message":""}
<form id=updater>
message: <input type=text name=message value="15"><br>
event type: <select name=type>
<option value=start>start</option>
<option value=update>update</option>
<option value=finish>finish</option>
</select><br>
<button>send message</button>
</form>
<div id=buildStatus title="Building">
<div class=text></div>
<div class=progress></div>
</div>
<div id=messages></div>
</body>
</html>
The PHP:
<?php
header('Content-Type: text/event-stream');
define('TYPE_BROADCAST','b');
define('MAX_FAILURES',30);//30 seconds
define('MAX_WAIT',30);//30 seconds
define('MAX_START_WAIT',6);//30 seconds
/*
* URL arguments:
* type
*/
include '../libconfig.php';
session_write_close();
if(!App::loggedIn() || !App::user()){
printEvent(0,'finish','Login session has expired.');
}
if($_GET['type']==TYPE_BROADCAST){//not needed;specific to the app I am creating
$db=db_get_connection();
$stm=new PDOStatementWrapper(db_prepare($db,'SELECT * FROM updates WHERE user_id=:user_id AND evt_id>:last_id'));
$args=array(':user_id'=>App::user()->getId(),':last_id'=>0);
$stm->bindParam(':user_id',$args[':user_id'],PDO::PARAM_INT);
$stm->bindParam(':last_id',$args[':last_id'],PDO::PARAM_INT);
$failures=0;
$nomsg=0;
if(!isset($_SERVER['HTTP_LAST_EVENT_ID'])){
$start=new PDOStatementWrapper(db_prepare($db,'SELECT * FROM updates WHERE user_id=:user_id ORDER BY evt_id DESC'));
$start->bindValue(':user_id',$args[':user_id'],PDO::PARAM_INT);
$startwait=0;
while(1){
if($startwait>MAX_START_WAIT){
printEvent(0,'finish','Timed out waiting for the process to start.');
return;
}
sleep(5);
$startwait++;
if(!$start->run()){
printEvent(0,'finish','DB error while getting the starting event.');
return;
}
while($start->loadNext()){
if($start->get('evt_type')=='finish')continue 2;
if($start->get('evt_type')=='start')break;
}
if($start->get('evt_type')=='start'){
$args[':last_id']=$start->get('evt_id');
printEvent($start->get('evt_id'),'start',$start->get('evt_msg'));
break;
}
}
}else
$args[':last_id']=$_SERVER['HTTP_LAST_EVENT_ID'];
if($args[':last_id']===0){
printEvent(0,'finish','ll');
exit;
}
while(1){
sleep(1);
if(!$stm->run()){
$failures++;
if($failures>MAX_FAILURES){
printEvent(0,'finish','Max failures reached.');
break;
}
}
if($stm->loadNext()){
$failures=0;
$nomsg=0;
do{
if($stm->get('evt_type')=='finish')break;
$args[':last_id']=$stm->get('evt_id');
printEvent($stm->get('evt_id'),$stm->get('evt_type'),$stm->get('evt_msg'));
}while($stm->loadNext());
if($stm->get('evt_type')=='finish'){
printEvent($args[':last_id'],'finish',$stm->get('evt_msg'));
break;
}
}else{
$nomsg++;
if($nomsg>MAX_WAIT){
exit;//TODO: test
}
}
}
}else{
printEvent(0,'close','Unknown event type.');
}
function printEvent($id,$name,$data){
echo "id: $id\nevent: $name\n";
if(is_array($data)){
foreach($data as $datum)
echo "data: $datum\n";
echo "\n";
}else
echo "data: $data\n\n";
flush();
if(isset($_SERVER['HTTP_X_REQUESTED_WITH']) &&
$_SERVER['HTTP_X_REQUESTED_WITH']=='XMLHttpRequest')exit;//ajax request. Need to kill the connection.
}
In case you were wondering about PDOStatementWrapper the source for it is here. Sorry it doesn't include anything integrated with CodeIgniter.

Categories