I am making my college project on Air Quality Monitoring System, in that data (say some integer value) has to be taken from sensing unit to a webpage.
What I want
Is that the script called upon by this url http://localhost/AQProject/recordupdate.php?val=2 updates a web page displaying the content. Now I know I can save that data in database and run ajax based query every two seconds to check for update, but I want that update to be pushed by server.
What have I done:
I have tried Server sent events. Here's what i tried
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
if($_SERVER["REQUEST_METHOD"]=="GET")
{
if(empty($_GET["val"])) die ("Empty Value from source");
else
{
$v = $_GET['val'];
echo "data: The Pollution stub value is {$v}".PHP_EOL;
ob_flush();
flush();
}
}?>
and html has script
<script>
if(typeof(EventSource) !== "undefined") {
var source = new EventSource("recordupdate.php");
source.onmessage = function(event) {
document.getElementById("result").innerHTML = event.data +
"<br>";
};
} else {
document.getElementById("result").innerHTML = "Sorry, your browser does not support server-sent events...";
}
</script>
Now, I have figured out this much that (correct me If i am wrong) it won't work because when another client (sensing unit) calls for recordupdate.php its a different instance of that script than that called by webpage client.
Is there any possible way of doing this using server sent events? Or I absolutely need to dig into websockets, node.js etc. Thanks in advance
What you want to do is not quite as easy as you hoped, but this is still a job for which SSE is suited. You don't need to use sockets, and don't need to use ajax polling.
But you do need some database store, on the server, that can be shared by PHP scripts. As installing a LAMP stack is so easy, I'd recommend using MySQL, even though it might be overkill for what you need. But your database could be as simple as a text file.
(To keep the below samples as small as possible, I've assumed your DB will be /tmp/val.txt, and I've not done any file locking, or checking for bad data. Just be aware that you need to do some work before putting this in production in an untrusted environment. I'd recommend pre-creating /tmp/val.txt to avoid any noise about files not existing.)
Your recordupdate.php has the job to record the value it is given:
<?php
if($_SERVER["REQUEST_METHOD"]=="GET")
{
if(empty($_GET["val"])) die ("Empty Value from source");
else file_put_contents("/tmp/val.txt", $_GET['val']);
}
You then have sse.php, which web clients connect to:
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
$prev = '';
while(1){
$v = file_get_contents("/tmp/val.txt");
if($v != $prev){
echo "data: The Pollution stub value is {$v}\n\n";
$prev = $v;
}
usleep(100000); //0.1s
}
This script is checking the text file for changes 10 times a second. As soon as it spots one it sends it to the client. (Mean latency is 0.05s plus network overhead.) Sleep for less time if you need lower latency.
The only change to your front-end HTML is to call "sse.php" instead:
<script>
if(typeof(EventSource) !== "undefined") {
var source = new EventSource("sse.php");
source.onmessage = function(event) {
document.getElementById("result").innerHTML = event.data +
"<br>";
};
} else {
document.getElementById("result").innerHTML = "Sorry, your browser does not support server-sent events...";
}
</script>
HTTP is one way protocol. Request from client to server only. Yes, absolutely need to dig into websockets, node.js etc.
Related
I have been making a small page on my server to display some photo albums. This is on an nginx server on a raspberry pi 4. When I try to access the page from my laptop or phone when they are on wifi, everything loads correctly. However, when I use my phone with LTE, for example, the php requests do not work. I checked with my laptop using my wireless hotspot and I had the same issue. I never get the "200" code that my browser is waiting for. I do not get an error either. It is as though the http request disappears. I have other pages on this same server where the php is working correctly, one of which is almost the exact same as this code. The php I am trying to use is one which returns file and album names as a long string. Expected output would be:
Siblings|Wyoming|Utah|Skiing|
This all works when accessed from my local network. In the past I have used much more elaborate php files to access security camera footage and also send shell scripts to turn a relay on and off. These worked from anywhere in the world, not just my network. I know very little about this stuff, so I'm hoping I am just missing something obvious that an expert can recognize immediately. :) I will include my code below.
getfiles.php
<?php
function clean_scandir($dir){
return array_values(array_diff(scandir($dir),array('.','..')));
}
$directory = $_GET['dir'];
$files = clean_scandir("/var/www/html/" . $directory);
foreach($files as $file){
$fileStr .= $file . "|";
}
echo $fileStr;
?>
And the javascript that is trying to use this php:
function getAlbums(){
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function(){
if(this.readyState == 4 && this.status == 200){
console.log("return packet = " + this.response);
var albumArray = this.response.split("|");
albumArray.pop(); //remove empty last element
for (var i = 0; i < albumArray.length; i++){
console.log("album " + i + " = " + albumArray[i]);
}
getThumbnail(albumArray);
setTimeout(() => {
populateAlbums(albumArray); //waits 1 sec for thumbnail requests to finish before loading thumbnails
}, 1000);
}
}
var urlString = "getfiles.php?dir=" + "photos/";
xmlhttp.open("GET", urlString, true);
xmlhttp.send();
}
The code never arrives at the console.logs that are within the big 'if' statement, I am assuming because the status never reaches 200. I do not get any other number like a 500 code. It just remains blank.
I have tried slowly modifying the php code. If the file is simply:
echo "php successful";
then it works. But for some reason the full code is causing issues. Sometimes the issues do not act the same each time either.
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.
I'm following the WC3 tutorial on server side events and am interested to know if i can use them to only deliver events/notifications when a php script is actually running, i.e. executing code. Ideally i'd like to use server side events to show script execution progress and avoid server polling altogether.
Currently my very simple client code is as follows:
<!DOCTYPE html>
<html>
<body>
<h1>Getting server updates</h1>
<div id="result"></div>
<script>
if(typeof(EventSource) !== "undefined") {
var source = new EventSource("https://xyz.php");
source.onmessage = function(event) {
document.getElementById("result").innerHTML += event.data + "<br>";
};
}
</script>
</body>
</html>
and my client code is as follows:
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
function send_message()
{
$time = date('r');
echo "data: The server time is: {$time}\n\n";
flush();
}
send_message();
?>
I know the above is an extremely simple example however I can't figure out how to start and stop the notifications and, in turn only do this when a server side script is running - a simple server script example would be to only send notifications every second when a timer counts from 1 to 10 and then stop.
Is this at all possible?
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've done created a webpage, set up appache2 on ubuntu server so I can view this page over the internet. I've installed php5 and MySQL and would like to access information in the database on the webpage that I've created.
Right now, I've got a file test.php that accesses the database and puts some of the information into variables. I've scripted using javascript something that will change the webpage content at the click of a button.
Now, the webpage crashes whenever the button is pushed as it says the variables are undefined or null references. Fair enough, but my question is how does one access variables on a .php file through the webpage? Can a browser use information in the .php file if I script it into the page?
I was told that the php file would be parsed automatically. I'm guessing that server side this page is being accessed but I can use it through web browser.
Edit:
//check connection
if (mysqli_connect_errno()){
echo "failed to connect to MySQL: " . mysqli_connect_error();
}
$grab = mysqli_query($con, "SELECT * FROM table");
$row = mysqli_fetch_array($grab);
$name = $row["name"];
$color = $row["color"];
$price = $row["price"];
$n1 = $name[0];
$c1 = $color[0];
$p1 = $price[0];
?>
Ok so I changed the php file to this, so now all it is doing is defining variables. I installed a couple of MySQL mods and no problems now.
next issue is how do I get use php variables in javascript
function load(){
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", "test.php", true);
xmlhttp.send();
xmlhttp.onreadystatecahnge = function(){
if(xmlhttp.readyState == 4 && xmlhttp.status == 200){
document.getElementById("itemNameLink1").innerHTML = "<?php echo $n1;?>;
}
}
}
So onload this ajax function should run and change itemNameLink1 to the php variable $n1, only it doesn't and I just get an empty string. Everything should be set up right but using the php variable seems impossible. would it be any easier with the jquery get command, I'm guessing that unless I sort this out I'm gonna struggle.
I'm also assuming a few things, I've checked error logs and the php file is active assuming I've connected right it should be accessing the database. I'm very new so I do not know how to test this.
I'm also assuming that when php file is in the server webpage file directory. that it is automatically working. again very new to setting up a server so using ubuntu server and being familiar with all the commands that I need to use or how apache2 operates is difficult for me.
PHP Is executed on the server, your client receives the result as a plain text/html document.
Your browser runs the javascript when it received the plain document, so you can't access PHP vars directly with javascript.
But you could set javascript variables when the page is generated on the server like this
<?php $myPhpVar = 'Hello World'; ?>
<script>
//This line would result in var test = "Hello World"; when send to client
var test = "<?=$myPhpVar?>";
alert(test);
</script>
Furthermore you can execute requests to your server with javascript (so you can read the result from test2.php as example, and use that somewhere on your page). http://en.wikipedia.org/wiki/Ajax_(programming)
Pure javascript: http://en.wikipedia.org/wiki/XMLHttpRequest
var request = new XMLHttpRequest();
request.onreadystatechange = function () {
var DONE = this.DONE || 4;
if (this.readyState === DONE){
alert(this.readyState);
}
};
var action = 'doSomethingOnServer';
request.open('GET', 'test2.php?action=' + action, true);
request.send(null);
Jquery: http://api.jquery.com/jquery.ajax/
<script>
var action = 'doSomethingOnServer';
$.ajax({
url: "test2.php?action=" + action,
}).done(function(result) {
alert(result);
});
<script>
For testing if your php works on your server create a file info.php (or something). and add this to the file
<?php phpinfo(); ?>
If you access that page you should get a page with a lot of information about your php configuration.
I'm not sure how you did install your php, but on a development machine you can change a few things in your php.ini that makes life easier
display_startup_errors = 1
display_errors = 1
error_reporting = E_ALL
See http://php.net/manual/en/errorfunc.configuration.php#ini.error-reporting when you change your php.ini don't forget to restart your apache
JSON Example:
data.php
<?php
$db_result = array(array('name' => 'record1'), array('name' => 'record2'));
echo json_encode($db_result);
?>
index.php
<script>
$.ajax({url: 'data.php', dataType: 'json'}).done(function(result) {
//result = an object from your database (in this case an array with objects with the property name)
alert(result);
alert(result[0].name);
}
</script>