apache, php config - php

I'm running a php application which responds to the client in about 1 minute (keeps loading all this time) . However the response is displayed all at once so I would like to know if there is any config in the apache server/php to display the response at the time is processed . For example I have
echo "test";
$rez = file_get_contents($URL);
do something ...
But the result from echo is displayed only after the application completed all the tasks(file_get_contents and everything else). So I need to config the server/php to display it at the execution time.

1) http://php.net/manual/en/function.flush.php
2) output_buffering = off for PHP
3) Disable gzip for PHP
4) Disable gzip in apache

use php's flush function
echo "test";
$rez = file_get_contents($URL);
flush();
http://php.net/flush

If $URL is sending data in real-time, and it isn't source of stopping anyway, you can try to connect by sockets (manually send HTTP request), and when reading incoming data to socket, you can display output continuously writing buffer used to receive socket data and flush()ing it to user browser.

Related

Switch from php-mod to php-fpm Output buffering problem

When using php-mod and fastcgi the code executes perfectly and every second i get an output but switching to php-fpm the code lags a few seconds before outputting depending on output size
Tried the following and combinations of
setting output buffer 0 in php ini
ob_implicit_flush
ob_start
ob_end_flush
header Content-Encoding = none
implicit_flush 1
ob_end_clean
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
while( true ){
$time = date('r');
echo "retry:1000\r\n";
echo "data: ".$time;
echo "\r\n\r\n";
ob_flush();
flush();
sleep(1);
}
?>
This is for a production server and php-mod is not an option i also got it to work in Fastcgi with
FcgidOutputBufferSize 0
is there a way to make the code work on php-fpm so the output is send immediately as in php-mod and fastcgi ?
P.S Running : Ubuntu 18.04, Apache 2.4.29, PHP 7.2
After a few days i have discovered the only way to get this to work in php-fpm is to fill the output buffer. This is really inefficient ! Let me explain :
Say you are using Server-send events and your output buffer is 4096, you process every second even if you do not return anything you still send about 4Kb output to client where mod_php and fast-cgi sends only data when there is an output.
If anyone else has this problem this is my best solution : run main site on php-fpm ex. example.com and make a sub-domain ex. push.example.com and setup fast-cgi / php_mod[NOT RECOMMENDED PRODUCTION] on sub-domain now you can keep the connection open and process data without sending output to client.
PS. I saved Session variables in database so both domain and sub-domain can access it see https://github.com/dominicklee/PHP-MySQL-Sessions the other thing is to let sub-domain send CORS. in PHP add header('Access-Control-Allow-Origin: https://example.com');

HTTP2 and continuing PHP execution

When running PHP, and you want it to immediately return HTML to the browser, close the connection (ish), and then continue processing...
The following works when the connection is HTTP/1.1, but does not when using Apache 2.4.25, with mod_http2 enabled, and you have a browser that supports HTTP/2 (e.g. Firefox 52 or Chrome 57).
What happens is the Connection: close header is not sent.
<?php
function http_connection_close($output_html = '') {
apache_setenv('no-gzip', 1); // Disable mod_gzip or mod_deflate
ignore_user_abort(true);
// Close session (if open)
while (ob_get_level() > 0) {
$output_html = ob_get_clean() . $output_html;
}
$output_html = str_pad($output_html, 1023); // Prompt server to send packet.
$output_html .= "\n"; // For when the client is using fgets()
header('Connection: close');
header('Content-Length: ' . strlen($output_html));
echo $output_html;
flush();
}
http_connection_close('<html>...</html>');
// Do stuff...
?>
For similar approaches to this problem, see:
close a connection early
Continue processing after closing connection
Continue php script after connection close
And as to why the connection header is removed, the documentation for the nghttp2 library (as used by Apache) states:
https://github.com/nghttp2/nghttp2/blob/master/doc/programmers-guide.rst
HTTP/2 prohibits connection-specific header fields. The
following header fields must not appear: "Connection"...
So if we cannot tell the browser to close the connection via this header, how do we get this to work?
Or is there another way of telling the browser that it has everything for the HTML response, and that it shouldn't keep waiting for more data to arrive.
How to return HTTP response to the user and resume PHP processing
This answer works only when web server communicates to PHP over FastCGI protocol.
To send the reply to user (web server) and resume processing in the background, without involving OS calls, invoke the fastcgi_finish_request() function.
Example:
<?php
echo '<h1>This is a heading</h1>'; // Output sent
fastcgi_finish_request(); // "Hang up" with web-server, the user receives what was echoed
while(true)
{
// Do a long task here
// while(true) is used to indicate this might be a long-running piece of code
}
What to look out for
Even if user does receive the output, php-fpm child process will be busy and unable to accept new requests until they're done with processing this long running task.
If all available php-fpm child processes are busy, then your users will experience hanging page. Use with caution.
nginx and apache servers both know how to deal with FastCGI protocol so there should be no requirement to swap out apache server for nginx.
You can serve your slow PHP scripts via HTTP/1.1 using a special subdomain.
All you need to do is to set a second VirtualHost that responds with HTTP/1.1 using Apache's Protocols directive : https://httpd.apache.org/docs/2.4/en/mod/core.html#protocols
The big advantage of this technic is that your slow scripts can send some datas to the browser long after everything else has been sent thru the HTTP/2 stream.

How can I disable gzip inside php code on HHVM? (eg setting content-encoding header)

I'm converting php code to hhvm. One page in particular sometimes needs to flush() a status-message to the browser before sending some emails and a few other slow tasks and then updating the status message.
Before hhvm (using php-fpm and nginx) I used:
header('Content-Encoding: none;');
echo "About to send emails...";
if (ob_get_level() > 0) { ob_end_flush(); }
flush();
// Emails sent here
echo "Emails sent.";
So the content-encoding stops gzip being used, then the flush sends the first message, then the second message is sent when the page ends.
Using HHVM (and nginx), setting the Content-encoding header works (it shows up in the browser), but either hhvm or nginx is ignoring it and sending the page as gzipped content, so the browser interprets the content-encoding=none with binary data.
How can I disable gzip inside php code on HHVM?
(I know I could turn it off in the config files, but I want it kept on for nearly every page load except a few that will run slower.)
While my suggestion would be to have different nginx location paths with different gzip configuration, here's a better alternative solution to achieve what you want to happen.
Better Solution:
It is often referred to as bad practice to keep a connection open (and the browser loading bar spinning) while you're doing work in the background.
Since PHP 5.3.3 there is a method fastcgi_finish_request() which flushes the data and closes the connection, while it continues to work in the background.
Now, this is unfortunately not supported yet on HHVM. However, there is an alternative way of doing this.
HHVM alternative:
You can use register_postsend_function('function_name'); instead. This closes the connection, and the given function will be executed in the background.
Here is an example:
<?php
echo "and ...";
register_postsend_function(function() {
echo "... you should not be seeing this";
sleep("10"); // do a lot of work
});
die();

PHP flush the output to browser

I work on a PHP project and I use flush().
I did a lot of search and found that PHP sends long outputs of scripts to the browser in chunk parts and does not send all the huge data when the script terminates.
I want to know the size of this data, I mean how many bytes the output must be for PHP to send them to browser.
It's not only PHP that chunks the data; it's actually the job of Apache (or Tomcat etc) to do this. That's why the default is to turn off the "chunking" in PHP and leave it to Apache. Even if you force a flush from PHP, it still can get trapped by Apache. From the 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.
There's a Wikipedia article on transfer encoding / chunking: http://en.wikipedia.org/wiki/Chunked_transfer_encoding
Apache gets more complicated with GZIP or deflate encoding; you'll need to hit an apache server as to how you chan configure it.
i think you are wrong
see this code
echo str_repeat(' ',1024);
for($i=0;$i<10;$i++){
echo $i;
flush();
sleep(1);
if you run it see that every 1 byte sent to browser and print
//the str_repeat is for browser buffer for showing data and nothing else

why echo does not show anything while php is busy

PHP Echo or Print functions does not show anything when php is busy with something (like when surfing the web with curl or something like that).
Later i discovered php does show the output when you execute your php on the command line:
php myscript.php
But right now i don't get any outputs from command line too!
Is there any kind of tricks or setting should be done to make php show the outputs?
Chances are, it's caching the results (both in PHP and the web server) and not actually sending them to the browser yet. the best suggestion I can give is this chunk from my code:
/**
* Act as a "breakpoint" in the code, forcing everything to be flushed to the browser
*/
function breakpoint() {
global $debug;
if ($debug) { // So that it doesn't slow down extracts
ob_flush();
flush();
sleep(.1);
}
}
The $debug stuff is if we're running the page in debug mode, specific to our website.
The two main thing you need are ob_flush(), which will send PHP's buffer to the web server's buffer, and flush() which will cause the server to dump to the browser. (Note: if the browser caches before displaying anything, nothing can prevent this) The sleep is there to help make sure it doesn't get overloaded, and has a chance to flush properly.
See:
http://ca.php.net/manual/en/function.ob-flush.php
and
http://ca.php.net/manual/en/function.flush.php
Both PHP and your web server are likely to be caching the output of echo and print. This will often result in no output until the script completes.
Try looking at flush() to force the output out of PHP, but it still may get held up at the web server, so may not help...

Categories