I have a function in one of my phpunit tests that does this:
echo "Order id: ".$order->id."\n";
$email = $this->getOrderEmail($order->id);
while($email === null) {
echo "Sleeping for order id ".$order->id."\n";
$this->saything();
sleep(1);
$email = $this->getOrderEmail($order->id);
}
echo "Got email: ".$email->MessageID."\n";
It runs the same code for several orders. The saything() method just echoes time().
When I run it, the first time it executes the code, it echoes correctly. When it runs it for the second order however, it echoes the "Got email", so I know it has exited the loop, and then it appears to stop processing.
When I use xdebug to trace the execution, I see that it is somehow still in the loop - it calls saything, which calls time(), and is supposed to echo it (literally: echo time();) - but doesn't. So the time() call is happening, but the echo() isn't. It hits the sleep, then the getOrderEmail, which returns null, triggering the loop to repeat but NOT echoing the "sleeping for..." message.
So I can clearly see in the xdebug trace that it is stuck in an infinite loop, but nothing is coming through to stdout! Why not? Could there be a bug in php somewhere? I've tried calling flush(), but that did nothing. How do I debug this? Also: How can it still be in the loop, when it has already executed the line following the loop? I've checked the process list, and it's definitely not forking, so I can't think of anyway it can exit a loop, while still being in the loop, and call echo without echoing anything.
I am aware that the problem is probablysomewhere else in the code, but it's way too big to post the whole thing here. Any ideas on how I can figure this out?
From PHP Manual:
"flush() may not be able to override the buffering scheme of your web server and it has no effect on any client-side buffering in the browser. It also doesn't affect PHP's userspace output buffering mechanism. This means you will have to call both ob_flush() and flush() to flush the ob output buffers if you are using those."
You should try using ob_flush();
Related
When single-stepping through PHP code during debugging (e.g. in Netbeans) I want to see PHP output in my browser immediately. This can be achieved (at least when using PHP7.2 and Firefox) by including the following at the start of the PHP code:
ob_implicit_flush ();
while (#ob_end_flush());
This ensures that things like
echo "foo\n";
immediately result in 'foo' being displayed in the web browser rather than when the output buffer is due for a flush or the PHP code exits upon completion or error.
But is there a way to achieve this by editing php.ini so I don't have to include it in every bit of PHP code to be debugged? (I understand this will result in a performance penalty, but this is for development and debugging purposes only.)
Flushing the output buffer is an implicit action that the developer must make, so isn't something that can be toggled on or off in the php.ini.
However, PHP does have a feature called ticks, which allows the developer to register a callback function to be called every X lines of code that are executed.
See register_tick_function, where you can define your own callback function to perform the flush, and have it run in between every statement in your program. This will obviously kill performance, and there is probably a better way of achieving what you're trying to do.
Example:
declare(ticks=1);
function autoFlushBuffer() {
ob_implicit_flush ();
while (#ob_end_flush());
}
register_tick_function("autoFlushBuffer", true);
// The following lines will appear in your web browser one by one:
echo "one";
sleep(1);
echo "two";
sleep(1);
echo "three";
sleep(1);
Is there a way to immediately stop PHP code execution?
I am aware of exit but it clearly states:
Terminates execution of the script. Shutdown functions and object destructors will always be executed even if exit is called.
So what I want to achieve is to stop the PHP code execution exactly when I call exit or whatever.
Any help?
Edit: After Jenson's answer
Trial 1:
function newExit() {
__halt_compiler();
}
echo "start";
newExit();
echo "you should not see this";
Shows Fatal error: __HALT_COMPILER() can only be used from the outermost scope in which was pretty expected.
Trial 2:
function newExit() {
include 'e.php';
}
echo "start";
newExit();
echo "you should not see this";
e.php just contains __halt_compiler();
This shows startyou should not see this
Edit: Why I want to do this?
I am working on an application that includes a proprietary library (required through virtual host config file to which I don't have access) that comes as encrypted code. Is a sort of monitoring library for security purpose. One of it's behaviours is that it registers some shutdown functions that log the instance status (it saves stats to a database)
What I want to do is to disable this logging for some specific conditions based on (remote IP)
Please see the following information from user Pekka 웃
According to the manual, destructors are executed even if the script gets terminated using die() or exit():
The destructor will be called even if script execution is stopped using exit(). Calling exit() in a destructor will prevent the remaining shutdown routines from executing.
According to this PHP: destructor vs register_shutdown_function, the destructor does not get executed when PHP's execution time limit is reached (Confirmed on Apache 2, PHP 5.2 on Windows 7).
The destructor also does not get executed when the script terminates because the memory limit was reached. (Just tested)
The destructor does get executed on fatal errors (Just tested) Update: The OP can't confirm this - there seem to be fatal errors where things are different
It does not get executed on parse errors (because the whole script won't be interpreted)
The destructor will certainly not be executed if the server process crashes or some other exception out of PHP's control occurs.
Referenced in this question
Are there any instances when the destructor in PHP is NOT called?
whats wrong with return ?
echo "you will see this";
return;
echo "you will not see this";
You can use __halt_compiler function which will Halt the compiler execution
http://www.php.net/manual/en/function.halt-compiler.php
You could try to kill the PHP process:
exec('kill -9 ' . getmypid());
Apart from the obvious die() and exit(), this also works:
<?php
echo "start";
__halt_compiler();
echo "you should not see this";
?>
I'm not sure you understand what "exit" states
Terminates execution of the script. Shutdown functions and object destructors will always be executed even if exit is called.
It's normal to do that, it must clear it's memmory of all the variables and functions you called before. Not doing this would mean your memmory would remain stuck and ocuppied in your RAM, and if this would happen several times you would need to reboot and flush your RAM in order to have any left.
or try
trigger_error('Die', E_ERROR);
I'm debugging a PHP script that runs a couple SQL queries and emails a set of users. I'm sure this is a very basic thing, but every time I try to echo, print, or print_r it doesn't appear while running the script.
So say I have this in the script:
print("This should print");
echo "on the command line";
When I run the script via command line php script.php it doesn't actually print anything to the command line while running the script.
Is there a way of having PHP print to console? I feel like I'm missing something extremely basic here.
Thats the method of doing it.
Things to check for are output buffering
http://php.net/manual/en/function.ob-flush.php
Is that code actually being run ? Make sure it doesnt branch before it gets there
A good approach could be:
function log($message)
{
$message = date("H:i:s") . " - $message - ".PHP_EOL;
print($message);
flush();
ob_flush();
}
It will output to your terminal each line you call. Just use :
log("Something");
log("Another line");
The following code working fine for me.
<?php
print("This should print");
echo "on the command line";
?>
with tags.
I know it is old, but I am going post my own solution to this just in case if someone would run into similar situation. I had a problem that a legacy command line PHP script wouldn't print or echo anything to the terminal when DSN is incorrectly configured and the script got stuck for very long time (not sure how long, never waited for it to terminate by itself). After putting ob_end_flush() in the entry line of the script, the output came back to the terminal. So it turned out that all output was buffered and since the script stuck at some point, the output stayed buffered and so never went to the terminal.
I'm trying to figure out why this loop doesn't return anything to the browser:
while(1) {
echo "hello";
flush();
sleep(1);
}
I'm expecting it to return "hello" to the browser every second... am I wrong? Right now the page just seems to hang.
PHP only outputs after execution has finished. so all you are doing where is generating a new hello every milisecond, and since you never exit the loop, you never see the output.
To correct my answer and make you to understand better, and for the AJAX lovers...
you need and extra flush there.. the 'ob_' one:
<?php
while( 1 ):
echo "hello";
ob_flush( ); flush();
sleep( 1 );
endwhile;
This is the 'trick' for everyone who need to know ;)
The browser won't display anything until the entire page is received. PHP is not capable of what you're trying to accomplish.
In Javascript, this is pretty simple.
<script>
window.setInterval(function(){document.innerHTML += "<br> Hello"}, 1000)
</script>
You should realise that PHP is a scripting language in the sense that it returns the output only after completing the script. EDIT: Or after output buffers are filled, thanks #Marc B.
Regardless I would say it is wiser to use JS for this or if you really need your server, use AJAX requests.
Perhaps you should consider using Javascript? That will allow you to add content every second (do keep in mind that JS is run at the clientside though, so you might not want to make your operations all that expansive then.)
Alternatively you could consider using AJAX requests through for instance JQuery, but that might be outside the scope of this question...
Maybe is not to late to answer but if you want to flush every second here I give you a sample:
<?php
echo "Flushing every second ...\n";
flush( );
$seconds = array (0,1,2,3,4,5,6,7,8,9);
foreach ($seconds as $second):
echo $second . "\n";
sleep( 1 );
#ob_flush( ); flush( );
endforeach;
echo 'I flashed 10 second :P';
Valentin gave you the right answer (upvote him/accept his answer!), but didn't explain why. Here's the explanation:
Output buffering
PHP doesn't output to the browser immediately, it waits to have some amount of content to send to the browser (probably it sends in chunks of 1024, 2048 or 4096 bytes), or when the execution ends. Calling flush() makes PHP send the data, but there is more than one layer of buffering. One is the internal buffering (what I've just commented), but you can add more layers of buffering. Suppose this code:
<?php
echo "hi";
setcookie('mycookie', 'somevalue');
?>
The setcookie() function sends an http header to the browser, but it can't do it because in HTTP, the server (or the client, it is the same both ways) must send first all headers, a blank line, and then the contents. As you see, you are outputting some content (hi) before the header, so it fails (because the internal buffering follows the same order of execution).
You can add another layer of output buffering, using the php functions ob_*(). With ob buffering it only buffers content output, not HTTP headers. And you can use them to get the output of functions that directly output to the browser, like var_dump(). Also, you can nest layers of ob:
<?php
// start first level of output buffering
ob_start();
echo "nesting at level ", ob_get_level(), "<br />\n"; // prints level 1
echo "hi<br />";
ob_start();
echo "nesting at level ", ob_get_level(), "<br />\n"; // prints level 2
var_dump($_POST);
$post_dump = ob_get_clean();
// this will print level 1, because ob_get_clean has finished one level.
echo "nesting at level ", ob_get_level(), "<br />\n";
echo "The output of var_dump(\$_POST) is $post_dump<br />\n";
// in spite of being inside a layer of output_buffering, this will work
setcookie('mycookie', 'somevalue');
// flush the current buffer and delete it (will be done automatically at the
// end of the script if not called explicitly)
ob_end_flush();
Probably your PHP server has output_buffering enabled by default. See the configuration variables to turn it off/on by default.
Ok, Carlos criticize me because I didn't explained my answer but also his answer is to vague... with cookies, layers.. POST, ob_levels... :OO to much info with no real point about the real question of the user but I will tell you why your code is not working. Because you have set in the php.ini the output buffering something like:
output_buffering = On
or
output_buffering = 4096 (default setting on most distributions)
Thats why you need the extra 'ob_flush( )', to get rid of any garbage output..
so... To make your code work you have 2 options:
1). set output_buffering = 0 or Off (if you have access to the php.ini)
2). ob_flush many times as layers of buffering you have
If you don't know how many layers you have you can do something like:
while (#ob_end_clean( ));
and clean every garbage you can have, and then your code will work just fine..
Complete snipp:
<?php
while (#ob_end_clean( ));
while(1) {
echo "hello";
flush();
sleep(1);
}
Cya..
Adding to all the other answers,
To do asynchronous Server push to clients you'll need to use WebSockets. It's a vast subject and not fully standardized, but there are certainly ways of doing it. If you are interested search for PHP Websockets.
I have a php file that is fired by a cronjob every minute.
When the php file is fired it updates the database, sleeps, etc
It is programmed like this:
$start = microtime(true);
set_time_limit(10);
for($i=0;$i<5;$i++)
{
updateDB();
time_sleep_until($start + $i + 1);
}
If this piece of code is run i don't see any changes happening in the database. Another thing i notices is when i echo something out i is printed when the loop is ended in one piece.
[edit] I tried using flush and ob_flush, but it still didn't print line for line[/edit]
What can i do to avoid these errors. The database needs to be updated.
Another thing i was wondering is what the best way is to log this kind of thing. Can i log the results to a log file.
The loop itself looks fine. If it isn't updating your database, the error must be in your updateDB() function.
As to the echo thing. The output of scripts is often buffered. To force PHP to print it right away, you can call either call flush() whenever you want the output flushed, or you can just call ob_implicit_flush() at the top of the script and it will flush automatically every time you print something.
Also, if you are calling the script via a browser, the browser itself may further buffer the response before showing it to you.
And as to the logging, the simplest way is to pick a file somewhere and just use file_put_contents() to print whatever you want logged. Note the FILE_APPEND flag for the third parameter.
Looks like you are running from command line, in this case you may want to write to stderr so that there is no buffering. $stderr = fopen('php://stderr', 'w');
In the case of logging, just open a file, write to it, and close it. (fopen, fwrite, fclose);