I would make a simple clock with sent-event my code is:
The client and server is on LAN, and the browser is iceweasel v.38.7.1.
php:
<?php
header("Content-Type: text/event-stream");
header("Cache-Control: no-cache");
header("Connection: keep-alive");
function sendMsg($msg) {
echo "retry: 1000\n";
echo "data: $msg" .PHP_EOL;
echo PHP_EOL;
ob_flush();
flush();
}
sendMsg(date("H:i", time()));
js
(function get_time()
{var source = new EventSource('/config/rtc/get_time.php');
source.addEventListener('message',function (event)
{document.getElementById("orologio").innerHTML=event.data;},false);
source.addEventListener('error', function(event) {
if (event.readyState === EventSource.CLOSED)
{get_time();}},false);
})();
The clock work for 30-45 minutes, after it stop,
Where I did go wrong?
thanks.
Your PHP script should look like:
<?php
header("Content-Type: text/event-stream");
header("Cache-Control: no-cache");
header("Connection: keep-alive");
function sendMsg($msg) {
echo "retry: 1000\n";
echo "data: $msg" .PHP_EOL;
echo PHP_EOL;
ob_flush();
flush();
}
while(true){
sendMsg(date("H:i", time()));
sleep(1);
}
Otherwise your PHP script is constantly closing (which totally does away with the point of using SSE), the SSE socket closes, and the browser then auto-reconnects. Theoretically ad infinitum, but possibly something gets fed up after 30 minutes :-)
What I thought the problem was going to be was script time-out. So at the top of your PHP script you should add:
set_time_limit(0);
Again, this is saying you want the PHP script to run forever, that the infinite loop is by design, and not a mistake.
Related
I would like to refresh my static web page running on apache when the index changes. I've already tried to use server-side events, where I had a PHP file checking if the index changed and if yes, it sent the event to the webpage. This works exactly how I want, but there is a problem. Because the page is used by a lot of people sometimes (tens or up to a hundred opened tabs), it quickly starts to spam many apache processes. Then, it reaches the limit, and the apache freezes.
The question is how to handle this. If a user closes the tab, the process is killed, however, if not, the apache freezes.
The PHP script looks like this (it is checking two things, first, if the file chenged, or second if the status is something. As I said, this works fine, the problem is its lagging the server):
<?php
session_start();
session_write_close();
ignore_user_abort(false);
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
$filename = "index.html";
while(True){
if ( connection_aborted() ){
exit();
}else{
try{
$string = file_get_contents("current_status.json");
$json = json_decode($string, true);
$pom1 = $json["state"];
$t1 = shell_exec("date -r index.html");
sleep(3);
$pom2 = $json["state"];
if($t1 != shell_exec("date -r index.html")) {
sleep(2);
echo "data: file changed \n\n";
} else if($pom2=="ready") {
sleep(2);
echo "data: new shot available \n\n";
} else {
echo "heartbeat";
}
ob_flush();
flush();
}
catch (\Error $e){
echo "data: error, json not available \n\n";
}
}
}
ob_end_flush()
?>
Then, there is a classical javascript function in the index file with event source on the PHP file.
My question is, how can I do this to not make apache crashing? Can I somehow set up SSE to handle it? I know I can allow more processes on apache, but my resources are limited.
Is there any other way how to do this? For example, live.js works as well, but the problem is the sam, a lot of processes when opened multiple times.
Yes, I can see how this would put far more strain on your server than necessary.
What you should do is poll for changes from javascript. You send an asynchronous request for the last time the index file changed from your javascript. You do it once when the page loads and store the time. Then you check again on an interval and compare the result with the first one. If it changed you refresh the page.
The PHP script should get the last change date, output it and exit - no continuously running PHP scripts.
Here is what the PHP file should look like:
<?php
header('Content-type: text/plain');
echo filemtime('index.html');
?>
Keep this minimal. The built in filemtime function is more efficient than running shell_exec commands.
Here is an example javascript:
chk_index_change_time(false);
function chk_index_change_time(last){
fetch('http://yourdomain.com/yourpath/get_index_change_time.php')
.then(res => res.text())
.then((index_change_time) => {
if ((false !== last) && (last != index_change_time)){
location.reload();
} else {
setTimeout(chk_index_change_time, 3000, index_change_time);
}
});
}
Feel free to error handling or whatever, but this will work. I used a timeout here instead of interval so that if the server is slow the server response time doesn't come out of the 3 second delay.
So I am using SSE EventListener, Where this Script will Listen to OnMessage Event that happens at respond.php
if(typeof(EventSource !== "undefined")){
var source = new EventSource('respond.php');
source.addEventListener('message', function(e) {
console.log(e.data);
}, false);}
else{
console.log("Sorry SSE is not working");
}
Respond.php
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
session_start();
if(isset($_POST['Body'])){
$myfile = fopen("data.txt","w");
$input = $_POST['Body'];
fwrite($myfile,"$input");
fclose($myfile);
echo "data: $input\n\n";
ob_flush();
flush();
}
This respond.php code basically say when this php gets an POST variable ready then write it to a data.txt then echo the data. I can see whenever I post an $_POST['Body'. data.txt gets update, So that means inside of the IF is getting executed BUT, the echo part just won't firing? The JAVASCRIPT onMessageListener is just not picking it up?(I did try to create an ELSE Part and echo something, and the Listener pick that up.)So I really don't know what is Happening here. Can someone please help?
I have used the following code to incrementally stream PHP output to JavaScript via AJAX:
ini_set('output_buffering', 'off');
ini_set('zlib.output_compression', false);
while (#ob_end_flush());
ini_set('implicit_flush', true);
ob_implicit_flush(true);
header("Content-type: text/plain");
header('Cache-Control: no-cache');
for($i = 0; $i < 1000; $i++) {
echo ' ';
}
// show output here
This works fine for me on localhost, but I've tried with three different remote servers, all of which don't work.
What is the reason for this? I can provide more code as necessary.
I'm experimenting with websockets and would like to detect if a user has navigated away from the page to the PHP stream script from running. Everything else is working fine.
Everything I try to do does not stop the PHP script from running (using Xampp locally).
I'm currently working with javascript's beforeunload, and PHP's connection_aborted(), connection_status() and even file_exists() (which is the only one that works currently!!!).
Until the script exists or I restart apache I cannot reload the page but it's the abort detection that I have to get working. Firebug reports the socket script has aborted but PHP just keeps ion running. Any help appreciated.
My javascript looks like this
function socket_open(){
if(!!window.EventSource){
var websocket = new EventSource('./ajax/progress.php');
websocket.addEventListener('message', function(e){
var data = JSON.parse(e.data);
console.log(data);
},false);
$(window).bind('beforeunload', function(){
websocket.onclose = function(){};
websocket.close();
});
}
}
And my PHP is like this.
./ajax/progress.php
function get_task_progress(){
$output = array();
//conditionally create some output
if(!empty($output)){
echo 'data: '.json_encode($output)."\n\n";
ob_flush();
flush();
}
sleep(1);
if(!connection_aborted() && connection_status()==0 && file_exists('1.txt')){
get_task_progress();
}
}
I seem to have solved it but echoing and flushing a no updates status on every request before the test for a live connection
if(!empty($output)){
$tasks_state = $tasks_new;
echo 'data: '.json_encode($output)."\n\n";
}else{
echo 'data: '.json_encode(array('e'=>0))."\n\n";
}
ob_flush();
flush();
sleep(1);
if(!connection_aborted() && connection_status()==0){
get_task_progress();
}
I have a IP Camera and I would like to show liveview at my webpage.
IP Camera don't allow for anonymous log in so I need to put username and password while connecting.
I have javascript:
<img src="http://user:password#camera_ip_address/cgi-bin/jpg/image.cgi?" width="640" height="480" name="refresh">
<script language="JavaScript" type="text/javascript">
image = "http://camera_ip_address/cgi-bin/jpg/image.cgi?"
function Start() {
tmp = new Date();
tmp = "?"+tmp.getTime()
document.images["refresh"].src = image+tmp
setTimeout("Start()", 100)
}
Start();
</SCRIPT>
And it works ok in firefox but:
http://user:password#camera_ip_number
don't work in other browsers (it popup a form to enter username and password).
But in PHP you can use user:password I've check it by using:
<?php
header('Content-type: image/jpeg');
print( file_get_contents( 'http://user:password#camera_ip_address/cgi-bin/jpg/image.cgi?' ));
?>
of course it shows only one frame but you don't have to enter username and password.
How can I log in into IP Camera using PHP ? If I could log in one time while enetering webpage, my javascript will work ok because browser will remember username and password until I close the browser.
I don't know how to send username and password to log in.
Sorry for my English.
Ok, so I've made it work using PHP and JavaScript. Maybe it will be helpful for someone else:
Save the PHP file as, for example, snapshot.php:
<?php
$img="http://user:password#camera_ip/cgi-bin/jpg/image.cgi?";
header ('content-type: image/jpeg');
readfile($img);
?>
In the HTML file, add this script:
<img src="http://domain.com/snapshot.php" width="640" height="380" name="refresh">
<script language="JavaScript" type="text/javascript">
image = "http://domain.com/snapshot.php"
function Start() {
tmp = new Date();
tmp = "?"+tmp.getTime()
document.images["refresh"].src = image+tmp
setTimeout("Start()", 300)
}
Start();
</script>
It works ok under every browser. If I set timeout to less then 300, there is some lag. I don't know why that would be caused by; maybe internet connection or website speed.
You may be able to use Apache mod_rewrite instead - Less overhead from the PHP stack, and probably generally faster. See this page for more information.
Choose one of these.
Apache .htaccess - Your page requests http://yoursite/livecam/image.jpg, which is run through Apache's proxy to your camera.
RewriteEngine on
RewriteBase /livecam/
RewriteRule ^image.jpg$ http://user:password#camera_ip_address/cgi-bin/jpg/image.cgi [P]
ProxyPassReverse /livecam/image.jpg http://user:password#camera_ip_address/cgi-bin/jpg/image.cgi
In PHP, create a file called image.php - Your page requests http://yoursite/image.php, which streams the image to whatever requests it.
<?php
$file = 'http://user:password#camera_ip_address/cgi-bin/jpg/image.cgi';
if (file_exists($file)) {
header('Content-Type: image/jpeg');
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
ob_clean();
flush();
readfile($file);
exit;
}
?>
Both will proxy the image through your server. It's generally bad practice to give the username and password on any public page, even if an attacker can't damage anything of concern.
See readfile() on PHP.net
Your code would look like (replace image.php with livecam/image.jpg if using the Apache version). I also shortened your code a bit.
<img src="http://yourserver/image.php" width="640" height="480" name="refresh">
<script language="JavaScript" type="text/javascript">setTimeout(function() {document.images["refresh"].src = "http://yourserver/image.php?"+math.random();}, 100);</SCRIPT>
IP:port/cgi-bin/jpg/image.cgi?&user=XXX&pwd=XXX
IP:port/cgi-bin/jpg/image.cgi?&usr=XXX&pwd=XXX
IP:port/snapshot.cgi?&user=XXX&pwd=XXX';
IP:port/cgi-bin/CGIProxy.fcgi?cmd=snapPicture2&usr=XXX&pwd=XXX';