I have a php script that is running in CLI and I want to display the current percent progress so I was wondering if it is possible to update the STDOUT to display the new percent.
When I use rewind() or fseek() it just throws an error message.
See this code:
<?php
echo "1";
echo chr(8);
echo "2";
The output is only 2 since "chr(8)" is the char for "backspace".
So just print the amount of chars you need to go back and print the new percentage.
Printing "\r" works too on Linux and Windows but isn't going to cut it on a mac
Working example:
echo "Done: ";
$string = "";
for($i = 0; $i < 100; ++$i) {
echo str_repeat(chr(8), strlen($string));
$string = $i."%";
echo $string;
sleep(1);
}
Output \r and then flush to get back to the first column of the current line.
Writing to a console/terminal is surprisingly complex if you want to move backwards in the output raster or do things like add colours - and the behaviour will vary depending on the type of console/terminal you are using. A long time ago some people came up with the idea of building an abstract representation of a terminal and writing to that.
See this article for details of how to do that in PHP.
Related
I'd like to be able to show a progress meter in a simple PHP script on the command line. Instead of seeing
Progress: 0%
Progress: 1%
etc...
I'd like just the number to change, and replace the previous number, much like git clone does for example Resolving deltas: 100% (8522/8522), done..
While searching for this I found the same question answered in Perl, which is perfect, but I couldn't find it in PHP. Is it possible? If not, I'll resort to C.
Thanks
Update: If anyone's interested in the C++ version, it's here.
This can be done using ANSI Escape Sequences -- see here for a list.
In PHP, you'll use "\033" when it's indicated ESC on that page.
In your case, you could use something like this :
echo "Progress : "; // 5 characters of padding at the end
for ($i=0 ; $i<=100 ; $i++) {
echo "\033[5D"; // Move 5 characters backward
echo str_pad($i, 3, ' ', STR_PAD_LEFT) . " %"; // Output is always 5 characters long
sleep(1); // wait for a while, so we see the animation
}
I simplified a bit, making sure I always have 5 extra characters, and always displaying the same amount of data, to always move backwards by the same number of chars...
But, of course, you should be able to do much more complicated, if needed ;-)
And there are many other interesting escape sequences : colors, for instance, can enhance your output quite a bit ;-)
Just for the record though an old thread:
Instead of using fancy ANSI Escape sequencing to move the curser back I just move it back to the beginning of the line using "\r" instead of to the beginning of the next line "\n". Add a few spaces after your echo to overwrite anything that was there previously, like e.g. so:
for ($i=0 ; $i<=100 ; $i++) {
echo "Progress: $i % \r";
sleep(1);
}
I have a PHP script running via CLI that's working well, but it runs a couple long queries (2-5 minutes) that would ideally give you some idea that something is still happening. When iterating through results, I do have a function running that updates the progress, but when PHP is waiting for a query to return, silence ensues.
I don't need to know anything about when the query will complete, but some sort of indication on the CLI that it's doing something would be a huge gain (binking ..., or something). Possible?
I've found that using carriage returns \r without newlines to be extremely helpful. They reset the output to the beginning of the line, but do not move down a line, allowing you to overwrite the current text.
Please note that you'll need to pad the line to the full length, otherwise previous characters will still linger. For example:
$iteration = 0;
while (/* wait condition */) {
printf("Process still running%-5s\r", str_repeat('.', $iteration % 5));
sleep(1);
$iteration++;
}
echo "\n";
echo "Task completed!";
If you're using a for loop for processing, something like this would be much more useful:
// Display progress every X iterations
$update_interval = 1000000;
for ($i = 0; $i < $massive_number; $i++) {
// Do processing
if ($i % $update_interval == 0) {
printf("Progress: %.2f%%\r", (100 * $i / $massive_number));
}
}
For a command line application I am trying to ask a simple question using the following code (example is not real life, code, but resembles the "real" version):
echo "Do you want to quit? [Y]/N";
$handle = fopen ( "php://stdin", "r" );
$input = trim(fgets($handle));
if ( empty($input) ) {
$input = 'Y';
echo "Y\n";
}
The result I want, is the following - When a user does -NOT- provide input:
Do you want to quit? [Y]/N: N // User only hits enter, not 'N'..
What I get is:
Do you want to quit? [Y]/N: // User only hits enter, not 'N'..
N
So the question is: How do I force echo 'Something'; to NOT print a newline after the echo.
Basically I need the equivalent of bash's echo -n '...' (does not print the trailing newline).
To understand why is it so - you need to understand that there are two things: STDIN and STDOUT that are involved into program. And - yes, php does not add new lines. With simple echo "foo"; you'll get exactly "foo", without new line.
But why are you seeing new line then? Simple: because you've pressed "it". That is: you've pressed "enter" key, terminal got it and printed it. Your program, of course, also got it, but at that moment the "key" is already printed.
What can you do? On that step: nothing. It's already done and that's it. You'll see it in your screen. However, yes, there is a trick that I can suggest. You can use stty to maintain behavior, when you can control the input and/or output. Combined with system() you'll get the idea.
Here we are with code:
function emulatePrintable()
{
$result = '';
while($c = trim(fgetc(STDIN)))
{
echo($c);
$result.=$c;
}
return $result;
}
system('stty -echo');
echo("Do you want to quit? [Y]/N ");
$result = emulatePrintable();
if($result==='')
{
echo("You didn't type anything!");
}
echo "\n"; //<--- this is to delimit program's end of work
system('stty echo');
What's happening? You're doing this:
Suppress any input printing with stty -echo. This is the trick. You're suppressing only input display, not output display. That is why you'll be able to see echo() strings from PHP
Emulating output for printable characters. That is: you still want to show what user is typing (your Y or N) - but you want to skip new line. Simple emulatePrintable() will do the work (may be not the best name, but at least I've tried)
After you've got the input (it's interrupted with EOL, for example) - you can examine what is it. If it's an empty string, then you've caught it: user typed nothing.
Now, do not forget to enable input display with stty echo - otherwise.. well, you'll end with "non-working" terminal.
Benefit: with this you'll be able even to decide, to print character or not (for example, to restrict only Y and N for output).
So this is the solution for unix-based OS. In Win - best of luck to you. You may check this page for console modes & related stuff, but I'm not sure it will work (since have not tested).
I ran into an interesting (well at least in my opinion) problem.
I have a PHP script that should generate the formatting (eg. the absolute positioning values of each image so they get displayed next to each other in a logical pattern) and the image sources when run. When completed it would load the appropriate image path from an sql db but currently I have a problem with this at this point.
Currently my script looks something like:
for ($i=0; $i<(866+1+866); $i++){
for ($j=0; $j<1001; $j++){
$data .= "<div id=\"tac-".$j."\"><img src=\"default_tactical.png\"/></div>";
}
}
As you can see it's rather basic at this point, as I only wanted to test if I can get the images in place.
Also the $data is a variable that my template simply echo-es to the browser.
The problem with all this is that my server runs out-of memory whenever I try to run this script.
So what's the problem? Or rather: how can I have a lot of images in a webpage without running out of memory?
Try changing it to:
for ($i=0; $i<(866+1+866); $i++){
for ($j=0; $j<1001; $j++){
echo "<div id=\"tac-".$j."\"><img src=\"default_tactical.png\"/></div>";
}
}
It should not run out of memory since it's not storing anything, just directly outputs it.
EDIT: Since you can't modify the code, just try raising the memory limit somewhere in the code (can be any PHP code that is executed before your loop).
#ini_set("memory_limit", "512M");
Look at it this way, you've got 2 nested loop, and are building a string inside.
866+1+66 = 1733 x 1002 = 17,364,66 iterations
17,364,666 iterations * 40 chars = ~70 megabytes
Either DON'T build the string at all once, or at least split it into chunks, e.g.
for ($i = ....) {
for ($j = ....) {
... build string here
}
echo $string
$string = ''; // reset to empty string and start over
}
While you haven't echo your $data, you haven't load image, it's just a string. It's the navigator which going to load each image after PHP processing. Your PHP is executed in the server and client load images. It's your variable $data which is out of memory.
Try like this :
for ($i=0; $i<(866+1+866); $i++){
for ($j=0; $j<1001; $j++){
echo "<div id=\"tac-".$j."\"><img src=\"default_tactical.png\"/></div>";
}
}
I am helping to build a Joomla site (using Joomla 1.5.26). One of the pages are really really big. As a result, PHP just stops working without any error and all previously printed strings are ignored. There is no output at all. We have display_errors set to TRUE and error_reporting set to E_ALL.
I found the exact line where PHP breaks. It's in libraries/joomla/application/component/view.php:196
function display($tpl = null)
{
$result = $this->loadTemplate($tpl);
if (JError::isError($result)) {
return $result;
}
echo $result;
}
Some information:
Replacing echo $result; with echo strlen($result); works. The length of the string is 257759.
echo substr($result, 0, 103396); is printing partial content.
echo substr($result, 0, 103397); results in no output at all.
echo substr($result, 0, 103396) . "A"; results in no output at all. So splitting string into chunks is not a solution.
I have checked server performance during the execution of the script. CPU usage is 100% but there's plenty of memory left. PHP memory limit is 1024M. output_buffering is 4096 but I tried setting it to unreasonably high number - dies at exact same position. Server runs Apache 2.2.14-5ubuntu8.10 and PHP 5.3.2-1ubuntu4.18. PHP runs as fast_cgi module.
I have never experienced something like that and Google search results in nothing also. Have any of you experienced something like that and know the solution?
Thanks for reading!
Maybe try exploding the string and looping through each line.
You could also try this, found on php.net - echo:
<?php
function echobig($string, $bufferSize = 8192)
{
// suggest doing a test for Integer & positive bufferSize
for ($chars = strlen($string)-1, $start = 0;$start <= $chars; $start += $bufferSize) {
echo substr($string, $start, $bufferSize);
}
}
?>
Basically, it seems echo can't handle such large data in one call. Breaking it up somehow should get you where you need to go.
what about try using print_r rather than echo
function display($tpl = null)
{
$result = $this->loadTemplate($tpl);
if (JError::isError($result)) {
return $result;
}
print_r($result);
}
I have tested this on the CLI and it works fine with PHP 5.4.11 and 5.3.15:
$str = '';
for ($i=0;$i<257759;$i++) {
$str .= 'a';
}
echo $str;
It seems a reasonable assumption that PHP itself works fine, but that the output buffer is too large for Apache/fast_cgi. I would investigate the Apache config further. Do you have any special Apache settings?
May be that?
Try something like this
php_flag output_buffering On
Or try to turn on gzip in Joomla!
Or use nginx as reverse proxy or standalone server :^ )
It seems I solved the problem by myself. It was somewhat unexpected thing - faulty HTML formatting. We use a template for order page and inside there is a loop which shows all ordered products. When there were a few products, everything worked great but when I tried to do the same with 40 products, the page did break.
However I still don't understand why the server response would be empty with status code 200.
Thanks for answers, everybody!