I'm trying to use output buffers in PHP to update the interface of the web page.
The simplified HTML structure is as follow:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<h1>Some Header Here</h1>
<?php
ob_implicit_flush(true);
$buffer = str_repeat(" ", 4096)."\r\n<span></span>\r\n"; // to ensure the browser to print ("flush") the output
ob_start();
echo '<p>Start operation</p>' . $buffer . PHP_EOL;
ob_flush(); flush(); ob_clean();
$response = shell_exec('a_long_running_command1'); // which will execute for around 3 minutes
echo '<p>Command 1 Response: ' . $response . '</p>' . PHP_EOL;
ob_flush(); flush(); ob_clean();
$response = shell_exec('a_long_running_command2'); // which will execute for around 5 minutes
echo '<p>Command 2 Response: ' . $response . '</p>' . PHP_EOL;
ob_flush(); flush(); ob_clean();
ob_end_flush();
echo '<p>Task Complete</p>' . PHP_EOL;
?>
</body>
</html>
whereas Command 1 & 2 are CPU-intensive tasks running on a Linux-based server.
However, once entered the page, the page is blank (and the browser (Chrome) indicates it keeps loading) until Command 1 is complete. How can I display the first <h1> header and the "Start Operation" heading first?
One more greedy question: is it possible for me to display the elapsed time on the page so that the user knows the command is still running?
I know I can achieve this via AJAX calls, but I don't want the user to:
refresh the page (which might lead to Command 1 & 2 being run for more than 1 instance in the server)
know the AJAX call so that he can replay the AJAX call
Related
I have the following html page
<?php session_start(); ?>
<html>
<body>
<?php
echo '<!-- cookies -->';
foreach($_COOKIE as $k => $v) {
echo '<!-- ' . $k . '=>' . $v . ' -->';
}
?>
</body>
</html>
which yields the following page source when I view the page with https://daley.ws/file1.php
<html>
<body>
<!-- cookies --><!-- PHPSESSID=>22u20jsi288vtk5epser56d2bn7leb6n --></body>
</html>
the following python code is run on my mac:
#!/Library/Frameworks/Python.framework/Versions/3.8/bin/python3
import urllib.request
REQ_HOST = "daley.ws"
DALEY_WS = 'https://daley.ws'
DALEY_WS_FILE1 = '{}/file1.php'.format(DALEY_WS)
DALEY_WS_FILE2 = '{}/file2.php'.format(DALEY_WS)
if __name__ == "__main__":
print(DALEY_WS_FILE1)
req = urllib.request.Request(DALEY_WS_FILE1,\
unverifiable=True, origin_req_host=REQ_HOST,\
method='POST')
with urllib.request.urlopen(req) as response:
data = response.read().decode()
print('data: {}'.format(data))
and produces the following output:
https://daley.ws/file1.php
data: <html>
<body>
<!-- cookies --></body>
</html>
why is the PHPSESSID cookie not present? and how do I fix the python code so that the page produces the proper output.
There is no issue with the Python code.
When you load the page the first time in the browser, the cookie is not in the source code. But when you refresh it (the second request, but with Cookie:) it is in the source code.
It's not present in HTML, because the PHP session cookie is NOT in $_COOKIE, unless you send the cookie in the first place with HTTP header Cookie:. Try session_id() in PHP or response.getheader("Set-Cookie") in Python to get the current session cookie.
I need to capture the output of a console command to be sent by email as well when requested. How can I do this?
How do I get the output generated from the following $this->info() calls?
$r = processData();
$this->info("\nSubmitted data:");
$this->info("SubmissionId: " . $r['submission_id']);
$this->info("Status: " . $r['status']);
Decided to just replace the $this->info() calls with a simple echo command and output buffer control. Looks good enough in the console and catches the data requested for emailing.
Example:
$r = processData();
if ($this->option('email-results'))
ob_start();
echo "\nSubmitted data:";
echo "\nSubmissionId: " . $r['submission_id'];
echo "\nStatus: " . $r['status'];
if ($this->option('email-results')) {
mail(
$this->option('email-results'),
'Results on ' . $start_time->toDateTimeString(),
ob_get_contents()
);
ob_end_flush();
}
an Artisan method could help:
\Illuminate\Support\Facades\Artisan::output()
I am just a amateur php programmer!
I have a specific requirement.
I want to control php output behaviour in my script.
What i want is this thing
myscript.php
echo "phase 1";// (output to browser immediately)
echo "Proceeding further....";
sleep (10);
echo "phase 2";// (output to the browser immediately)
sleep(10);
echo "phase end";
But what happens is all the output of echo gets dump after 20 second i mean complete output not sequencewise...
How can i output it in sequence wise.. i do not know what it is called ! Please also show a example if possible it helps in understanding
You might wanna take a look at some Websocket like Rachet. For a simpler version, you just use a combination of Javascript/Ajax and PHP.
EDIT: The simplest way; the jQuery/PHP way
As requested in the comments, this is a very simple, insecure way of achieving asynchronous server work/feedback.
Server-side
//doTheWork.php
switch($_POST['step'])
{
case 1:
$output = shell_exec('cat text.txt'); //Do whatever you need to do here
break;
case 2:
$output = shell_exec('ls');
break;
default:
$output = "No or invalid step declared";
}
echo $output;
Client-side
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Testing live feedback</title>
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script> <!-- Include your local version of jQuery -->
<script src="//code.jquery.com/jquery-migrate-1.2.1.min.js"></script>
</head>
<body>
<div id="console">
<h2>Output from server</h2>
<div id="console_output">
</div>
</div>
<script type="text/javascript">
var totalSteps = 5;
var currentStep = 0;
var url_to_server = "http://localhost/doTheWork.php";
function executeAndOutputData()
{
currentStep++;
if(currentStep >= totalSteps) return;
$.post(url_to_server, {step:currentStep}, function(response){
$("#console_output").append(response+"<br>");
executeAndOutputData();
});
}
executeAndOutputData();
</script>
</body>
</html>
Yes you can natively with PHP using flush functions.
Example with your code :
<?
echo "phase 1";// (output to browser immediately)
echo "Proceeding further....";
flush();
ob_implicit_flush(true);
ob_flush();
sleep (10);
echo "phase 2";// (output to the browser immediately)
sleep(10);
echo "phase end";
?>
edit : But, this is just to answer you. A such code is certainly fully useless and must be improved to remove sleep calls.
I am satisfied with Dencker answer but still i now know a simpler way by using only PHP.
Derived from http://www.codeproject.com/Tips/680085/Real-time-Updating-of-PHP-Output
// Turn off output buffering
ini_set('output_buffering', 'off');
// Turn off PHP output compression
ini_set('zlib.output_compression', false);
//Flush (send) the output buffer and turn off output buffering
while (#ob_end_flush());
// Implicitly flush the buffer(s)
ini_set('implicit_flush', true);
ob_implicit_flush(true);
echo "Start<br />";
echo str_pad("",1024," ");
echo "<br />";
ob_flush();
flush();
sleep(5);
echo "Program Output";
ob_flush();
flush();
And it does work without any server config and it is well suited for my need (temp). But i will be looking at the suggestion posted here.
On this page http://www.effectivewebsolutions.biz/video-spokesmodel.html if you put in your URL it opens it through fopen function and puts a video spokes-model on the website for demonstration purposes, here is the script.
<?php
$handle = fopen($_POST["url"], "r");
while($data = fread($handle, 1000000)){
$contents .= $data;
}
fclose($handle);
echo "<base href=\"{$_POST['url']}\">";
echo "\n\n";
echo "<!-- Begin inserted page -->";
echo "\n";
echo $contents;
echo "\n";
echo "<!-- End inserted page -->";
echo "\n\n";
echo '<script type="text/javascript" src="http://www.internet-spokesmodels.com/scripts/swfobject.js"></script>';
echo '<style type="text/css" media="screen">object { outline:none; } </style>';
echo "\n";
echo '<script type="text/javascript" src="http://www.internet-spokesmodels.com/actors/script/SabrinaEXAMPLESredshirt_350x500.js"></script>';
?>
However in Safari it only opens text version of the website (no css or images).
It doesn’t make sense why would browser make a difference in this case.
Any Ideas?
Probably because the page does not render valid HTML. When I tried it with http://www.google.ca, I got:
<base href="http://google.ca">
<!-- Begin inserted page -->
<!doctype html><html><head><meta http-equiv="content-type" ...
The DOCTYPE should be the first thing in the page, followed by a <html> tag with HTML content. The <base> tag should be within the <head> tag.
You can't blame Safari for displaying invalid HTML incorrectly.
The HTML code being returned should be identical across browsers, since browsers have nothing to do with server-side code. Check the validity of HTML. Also, sanitize your input as suggested meagar.
I am using ob_start()/ob_flush() to, hopefully, give me some progress during a long import operation.
Here is a simple outline of what I'm doing:
<?php
ob_start ();
echo "Connecting to download Inventory file.<br>";
$conn = ftp_connect($ftp_site) or die("Could not connect");
echo "Logging into site download Inventory file.<br>";
ftp_login($conn,$ftp_username,$ftp_password) or die("Bad login credentials for ". $ftp_site);
echo "Changing directory on download Inventory file.<br>";
ftp_chdir($conn,"INV") or die("could not change directory to INV");
// connection, local, remote, type, resume
$localname = "INV"."_".date("m")."_".date('d').".csv";
echo "Downloading Inventory file to:".$localname."<br>";
ob_flush();
flush();
sleep(5);
if (ftp_get($conn,$localname,"INV.csv",FTP_ASCII))
{
echo "New Inventory File Downloaded<br>";
$datapath = $localname;
ftp_close($conn);
} else {
ftp_close($conn);
die("There was a problem downloading the Inventory file.");
}
ob_flush();
flush();
sleep(5);
$csvfile = fopen($datapath, "r"); // open csv file
$x = 1;
// skip the header line
$line = fgetcsv($csvfile);
$y = (feof($csvfile) ? 2 : 5);
while ((!$debug) ? (!feof($csvfile)) : $x <= $y) {
$x++;
$line = fgetcsv($csvfile);
// do a lot of import stuff here with $line
ob_flush();
flush();
sleep(1);
}
fclose($csvfile); // important: close the file
ob_end_clean();
However, nothing is being output to the screen at all.
I know the data file is getting downloaded because I watch the directory where it is being placed.
I also know that the import is happening, meaning that it is in the while loop, because I can monitor the DB and records are being inserted.
Any ideas as to why I am not getting output to the screen?
You also need to check the PHP settings
some installs default to 4096, some default to off
output_buffering = Off
output_buffering = 4096
agreed with George but do check the above settings
Make sure that your output buffering doesn't start automatically. Run:
print ob_get_level ();
before ob_start (); if will will see something else then 0 you've got the answer.
Hey man I was also got stuck in this problem
and finally got the correct solution
here it is for you
you have to add content type for your page
you can do that by two ways
1. using html tag
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
Ex.
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Wp Migration</title>
</head>
<body>
<?php
for($i=0;$i<70;$i++)
{
echo 'printing...<br>';
ob_flush();
flush();
sleep(3);
}
?>
</body>
</html>
using php header function
<?php header( 'Content-type: text/html; charset=utf-8' ); ?>
Ex.
<?php
header( 'Content-type: text/html; charset=utf-8' );
for($i=0;$i<70;$i++)
{
echo 'printing...<br>';
ob_flush();
flush();
sleep(3);
}
?>
All the best
Ob_end_clean() discards the contents of the current output buffer and turns off the buffering.
You should use ob_end_flush() instead.
Add this line
header("X-Accel-Buffering: no");
worked for me.
You can edit it with the .htaccess file
To disable output buffering, modify the line as follows:
php_value output_buffering Off
php_value output_buffering 4096
worked for me. Thank you!
Check this site: Click Here
It's possible that your webserver is doing its own buffering. Probably with something like mod_gzip.
Here is some very simple test code:
<?php
echo 'starting...<br/>';
for($i = 0; $i < 5; $i++) {
print "$i<br/>";
flush();
sleep(2);
}
print 'DONE!<br/>';
If it takes 10 seconds for that page to load, rather than seeing a new line every 2 seconds, then it means that it is being cached by your webserver. For what you are trying to do, there is no need to use ob_start and ob_flush. Just call flush whenever you want to force the content to the browser. However, like I mentioned, if the webserver is waiting for the content to complete before sending, then that won't do anything for you.
Edit: Another possibility is that you're viewing the page from behind a corporate or ISP proxy/firewall that waits for the whole page before serving it (so that it can scan it to see if it looks like pornography, for example).