im experimenting with JSON Api's with PHP.
Im using a free Bitcoin price ticker api from Blockchain.
Its working but to refresh the data i need to refresh the page.
Would it be possible to auto-update the data without refreshing the page?
This is what i got now (its working)
<?php
$json = file_get_contents('https://blockchain.info/ticker');
$data = json_decode($json,true);
$priceUSD = $data['USD']['last'];
echo $priceUSD;
Thanks in advance, have a nice day!
King regards,
L Kenselaar
In order to refresh the data in your PHP array, you'll have to run a new HTTP request against your API from within the PHP code.
Without refreshing the page where your PHP renders, you would need to keep the connection open (which will only last for as long as your php.ini max_execution_time is and PHP can't edit data it has already sent, so the closest you could get is a news ticker that appends new lines at the bottom)
If all you want is a self-refreshing website, you'll have to use JavaScript (that can run infinitely and request new data from your PHP backend in regular intervals). Look for AJAX or XMLHttpRequests in general.
If you must stick to PHP you might want to run an independent process in background (checkout nohup or disown on Linux/Unix).
Your script would do something like:
<?php
while(true){
try {
$json = file_get_contents('https://blockchain.info/ticker');
$data = json_decode($json,true);
$priceUSD = $data['USD']['last'];
// Do the internal handling
// update your database, etc
}
catch (Exception $e) {
echo 'Error: ' . $e->getMessage() . "\n";
}
// wait for 5 seconds
sleep(5);
}
Keep in mind that PHP code runs in a blocking thread and this means that this process has to run aside of your web server.
However, if you wanted to both tasks at the same time (fetching and serving requests), you would have to consider alternatives like NodeJS.
Related
I have a Wordpress website with a working order system. Now I want to make an Android app which displays every new order in a list view as soon as the order was made.
The last two days I thought about the following solutions:
Simple HTTP GET requests every 10 seconds
Websockets
MySQL binary log + Pusher Link
Server Sent Events
My thoughts (working with a LAMP stack):
Simple HTTP requests are obviously the most ineffective solution.
I figured out that websockets and Apache aren't working well together.
Feels quite hacky and I want to avoid any 3rd party service if I can.
4. Looks like this is the optimal way for me, however there are some problems with Apache/php and Server Sent Events from what I experienced.
I tried to implement a simple demo script but I don't understand why some of them are using an infinite while loop to keep the connection open and others don't.
Here is an example without a loop and here with an infinite loop, also here
In addition to that, when I tested the variant with the infinite loop, my whole page won't load because of that sleep() function. It looks like the whole server freezes whenever I use it.
Does anyone have an idea how to fix that? Or do you have other suggestions?
That is the code that causes trouble (copied from here) and added a missing curly bracket:
<?php
// make session read-only
session_start();
session_write_close();
// disable default disconnect checks
ignore_user_abort(true);
// set headers for stream
header("Content-Type: text/event-stream");
header("Cache-Control: no-cache");
header("Access-Control-Allow-Origin: *");
// Is this a new stream or an existing one?
$lastEventId = floatval(isset($_SERVER["HTTP_LAST_EVENT_ID"]) ? $_SERVER["HTTP_LAST_EVENT_ID"] : 0);
if ($lastEventId == 0) {
$lastEventId = floatval(isset($_GET["lastEventId"]) ? $_GET["lastEventId"] : 0);
}
echo ":" . str_repeat(" ", 2048) . "\n"; // 2 kB padding for IE
echo "retry: 2000\n";
// start stream
while(true){
if(connection_aborted()){
exit();
}
else{
// here you will want to get the latest event id you have created on the server, but for now we will increment and force an update
$latestEventId = $lastEventId+1;
if($lastEventId < $latestEventId){
echo "id: " . $latestEventId . "\n";
echo "data: Howdy (".$latestEventId.") \n\n";
$lastEventId = $latestEventId;
ob_flush();
flush();
}
else{
// no new data to send
echo ": heartbeat\n\n";
ob_flush();
flush();
}
}
// 2 second sleep then carry on
sleep(2);
}
?>
I'm thankful for every advice I can get! :)
EDIT:
The main idea is to frequently check my MySQL database for new entries and if there is a new order present, format the data nicely and send the information over SSE to my android application.
I already found libraries to receive SSEs on android, the main problem is on the server side.
Based on your question I think you could implement SSE - Server sent events, which is part of HTML5 standard. It is a one-way communication from server to client. It needs html/javascript and a backend language, e.g PHP.
The client will subscribe on events and when subscription is up and running the server will send any updates from the input data. As standard the update will be visible each 3 seconds. This can be adjusted though.
I would recommend you to first create a basic functioning web-browser-client as a start. When and if it is working as you expect, only then you would judge about the effort of building the client as an app.
You would probably need to add functions on the client-side, such as start/stop the subscription.
My understanding of users not recommending the combination of (server sent events) and Apache is the lack of control how many open connections there are and what would control the continuously need of closing of connections. This could lead to sever server performance problems.
Seems using for example node.js would not cause that problem.
Here are some start link:
MDN:
https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events
Stream Updates with Server-Sent Events:
https://www.html5rocks.com/en/tutorials/eventsource/basics/
I managed to display the status of a server using FSOCKOPEN.
<?php
$ip = "0.0.0.0";
$port = "1337";
$online = '<font class="online" title="Server Online!">ONLINE</font>';
$offline = '<font class="offline" title="Server Offline!">OFFLINE</font>';
if (! $sock=#fsockopen($ip, $port, $num, $error, 0.25))
{echo "$offline";}
else
{echo "$online";}
?>
If the server with the IP "0.0.0.0" sends an error or does not respond within 1/4th of a second after the page has been loaded the Output will return OFFLINE, else it will return ONLINE.
The server status will update when the user refreshes the page.
Now I want to make it to update in real time (less than 7 seconds delay)
I know there is a very easy method to do that using <meta http-equiv=”refresh” content=”5" /> in the head tag.
But its pretty annoying that the COMPLETE page have to refresh and load everything again and its causing some unnecessary traffic.
Is there an easier way to do it?
You can use ajax and javascript in the client to open the PHP Script in the background and then update the element in the page with the result based on success/failure.
Take a look at jQuery and other library to do this easily.
Another option would be a simple <iframe /> to open another website as an element on the website.
Dont use ajax or any direct polling mechanism that will put more load on your server in terms of traffic.
What you can use is websockets to push data to a stream and read it in frontend
https://socket.io/
This can be done near realtime and your page will not be reuired to get updated every min.
Put PHP script in cron to run at required interval and end of it just push the output to sockets and catch them on frontend.
I have a PHP script that performs a connection to my other server using file_get_contents, and then retrieves and displays the data.
//authorize connection to the ext. server
$xml_data=file_get_contents("http://server.com/connectioncounts");
$doc = new DOMDocument();
$doc->loadXML($xml_data);
//variables to check for name / connection count
$wmsast = $doc->getElementsByTagName('Name');
$wmsasct = $wmsast->length;
//start the loop that fetches and displays each name
for ($sidx = 0; $sidx < $wmsasct; $sidx++) {
$strname = $wmsast->item($sidx)->getElementsByTagName("WhoIs")->item(0)->nodeValue;
$strctot = $wmsast->item($sidx)->getElementsByTagName("Sessions")->item(0)->nodeValue;
/**************************************
Display only one instance of their name.
strpos will check to see if the string contains a _ character
**************************************/
if (strpos($strname, '_') !== FALSE){
//null. ignoring any duplicates
}
else {
//Leftovers. This section contains the names that are only the BASE (no _jibberish, etc)
echo $sidx . " <b>Name: </b>" . $strname . " Sessions: " . $strctot . "<br />";
}//end display base check
}//end name loop
From the client side, I'm calling on this script using jQuery load () and to execute using mousemove().
$(document).mousemove(function(event){
$('.xmlData').load('./connectioncounts.php').fadeIn(1000);
});
And I've also experimented with set interval which works just as well:
var auto_refresh = setInterval(
function ()
{
$('.xmlData').load('./connectioncounts.php').fadeIn("slow");
}, 1000); //refresh, 1000 milli = 1 second
It all works and the contents appear in "real time", but I can already notice an effect on performance and it's just me using it.
I'm trying to come up with a better solution but falling short. The problem with what I have now is that each client would be forcing the script to initiate a new connection to the other server, so I need a solution that will consistently keep the information updated without involving the clients making a new connection directly.
One idea I had was to use a cron job that executes the script, and modify the PHP to log the contents. Then I could simply get the contents of that cache from the client side. This would mean that there is only one connection being made instead of forcing a new connection every time a client wants the data.
The only problem is that the cron would have to be run frequently, like every few seconds. I've read about people running cron this much before, but every instance I've come across isn't making an external connection each time as well.
Is there any option for me other than cron to achieve this or in your experience is that good enough?
How about this:
When the first client reads your data, you retrieve them from the remote server and cache them together with a timestamp.
When the next clients read the same data, you check how old the contents of the cache is and only if it's older than 2 seconds (or whatever) you access the remote server again.
make yourself familiar with APC as a global storage. Once you have fetched the file, store it in the APC cache and set a timeout. You only need to connect to the remote server, once a page is not in the cache or outdated.
Mousemove: are you sure? That generates gazllions of parallel requests unless you set a semaphore clientside to not issue any AJAX queries anymore.
I am building a WebService, using PHP:
Basically,
User sends a request to the server, via HTTP Request. 'request.php', ie.
Server starts php code asynchronously. 'update.php', ie.
The connection with the user is finished.
The code 'update.php' is still running, and will finish after some time.
The code 'update.php' is finished.
The problem is with php running asynchronously some external code.
Is that possible? Is there another way to do it? With shell_exec?
Please, I need insights! An elegant way is preferable.
Thank you!
The best approach is using message queue like RabbitMQ or even simple MySQL table.
Each time you add new task in front controller it goes to queue. Then update.php run by cron job fetch it from queue, process, save results and mark task as finished.
Also it will help you distribute load over time preventing from DoS caused by your own script.
You could have the user connect to update.php, generate some sort of unique ID to keep track of the process, and then call fsockopen() on itself with a special GET variable to signify that it's doing the heavy lifting rather than user interaction. Close that connection immediately, and then print out the appropriate response to the user.
Meanwhile, look for the special GET variable you specified, and when present call ignore_user_abort() and proceed with whatever operations you need in that branch of the if clause. So here's a rough skeleton of what your update.php file would look like:
<?php
if ( isset($_GET['asynch']) ) {
ignore_user_abort();
// check for $_GET['id'] and validate,
// then execute long-running code here
} else {
// generate $id here
$host = $_SERVER['SERVER_NAME'];
$url = "/update.php?asynch&id={$id}";
if ( $handle = fsockopen($host, 80, $n, $s, 5) ) {
$data = "GET {$url} HTTP/1.0\r\nHost: {$host}\r\n\r\n";
fwrite($handle, $data);
fclose($handle);
}
// return a response to the user
echo 'Response goes here';
}
?>
You could build a service with PHP.
Or launch a PHP script using bash : system("php myScript.php param param2 &")
Look into worker processes with Redis resque or gearman
I just started using SSE in my PHP pages. I can very easy send new data with this code:
while(true) {
if (isset($_GET["selectedName"]) && $_GET["selectedName"] != "empty") {
echo "data:current timestamp for user ".$_GET["selectedName"]." is ".time().PHP_EOL;
echo PHP_EOL;
ob_flush();
flush();
}
sleep(1);
}
But this means, that I'm sending data every second to the client and I have to run a loop. The string in the example is not much data. But later I want to connect to a database and pull stuff from there.
If I would pull something like a whole article (or message or what ever), I would produce a very big amount of data.
Now my question: How can I tell script to provide new data and send it to the client from another PHP script?
I created a little iOS app which uses a small API to send status updates to the server. I'd like one of the API scripts to tell the web interfaces event source script to send the new data.
And only, when I tell it to do so.
How can I achieve this?
Thanks for help, with kind regards, Julian
Regarding the fact I don't have MUCH stuff to send at once (a state number from 0 to 4 and a little message string), I decided to set a variable and check if anything changed:
static $oldStateString;
while(true) {
$result = mysql_query("SELECT * FROM st_workers");
$currentStateString = "";
while ($user = mysql_fetch_array($result)) {
$currentStateString .= $user["stateIndex"].":--;".$user["state"].":--;".$user["humanReadableName"].":__;";
}
if ($currentStateString != $oldStateString) {
echo "data:".$currentStateString.PHP_EOL;
echo PHP_EOL;
ob_flush();
flush();
$oldStateString = $currentStateString;
}
sleep(1);
}
BUT: I noticed that you have to start to event handler a little later, not <body onload="">. This produces errors in most browsers except Safari 6 and the current FireFox. The browser doesn't recognize that it's not loading anymore. So the "loading spinner" does not stop until like 5 minutes or more.