how can i detect a client disconnection in php. I have a web service that uses nusoap library and I want to detect web service client disconnection.
I try with this code:
ignore_user_abort(true); // Continue running the script even when the client aborts/disconnects
ob_flush();
flush(); // Clean PHP's output buffer
usleep(500000);
echo "0\r\n\r\n";
ob_flush(); // Clean output buffer
flush(); // Clean PHP's output buffer
if(connection_aborted() != 0) {
//do something
}
It works but it has 2 problem:
Flush() function adds additional header causing this warning: Warning: Cannot modify header information - headers already sent in .\lib\nusoap-0_9_5\lib\nusoap.php on line...
The response of my web service is not well formatted due to additional character that i send echo "0\r\n\r\n" to check client connection.
How can I resolve problems listed above? There are other ways to detect web service client disonnection?
Thanks
Related
I have a ZoneMinder media server that serve a live feed of CCTV's through http. It's response with an image stream (not video).
Now I making a third-party web application that needs that live stream feed to be displayed.
The problem I have here, is I need to integrate the system without making any browser request to the ZoneMinder server, I wan't to do it from the third-party application backend and serve them back in the browser.
I use PHP for the application and so far I get this code running:
$link = get_zoneminder_url_stream();
header("Content-Type: multipart/x-mixed-replace;boundary=ZoneMinderFrame");
$fd = fopen($link, "r");
while(!feof($fd)) {
echo fread($fd, 1024 * 5);
ob_start();
ob_end_flush();
ob_flush();
flush();
}
fclose ($fd);
I get the expected live image stream for the ZoneMinder server. But I get several problems.
When I start the live stream (executing the code above), the rest of my web application become unresponsive. All the request to the php script of the server can't be handled (it always 'pending' in the network tabs on the browser developer console), but still can handle other file (such as assets file) GET request.
I know that in this point, I get some problems with the PHP itself rather than the web server.
So my question is what is the best way to do a live stream request to another server from PHP server and throws back the stream as a response to the browser.
Thanks in advance
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.
I have some basic website tracking software that sends a JSON object with jQuery AJAX from a webpage cross-domain to a server where the data is processed by a php script. This is triggered on window.onbeforeunload.
When benchmarking my php script I have realised that the client website on a different domain is still waiting for the php script to finish running before loading the next page. For example, a visitor to a client site navigates to another page. We send the JSON object cross domain to the server to process it. If I add sleep(30); to my php script the client website will not load the next page until this php script finishes (30+ seconds).
I do not need to return any values after running this script so how can I ensure this php script runs without having any impact on the client site?
I hope I've explained myself well enough. Ask any questions if I haven't, thanks.
SOLUTION:
This is what worked for me (http://php.net/manual/en/features.connection-handling.php#93441):
ob_end_clean();
header("Connection: close\r\n");
header("Content-Encoding: none\r\n");
ignore_user_abort(true); // optional
ob_start();
echo ('Text user will see');
$size = ob_get_length();
header("Content-Length: $size");
ob_end_flush(); // Strange behaviour, will not work
flush(); // Unless both are called !
ob_end_clean();
//do processing here
sleep(5);
echo('Text user will never see');
//do some processing
For PHP-fpm:
To close connection with client (send response), but continue running script and processing some data, this function can help you - fastcgi_finish_request
For apache:
See this link - close a connection early
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
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.