APNs Server for handling streams from PHP script - php

I have a web server that sends push notifications to devices when certain actions are performed with a POST or GET. This works, but because of the nature of having to open an SSL connection to APNS, write all the tokens and exit, the actions that involve this operation are latent compared to those who do not. The latency is only a second or so, but a second is still significantly longer than say 100ms, which is how long it takes otherwise (if I comment out the APNS part).
It seems that it's also bad practice to open and close the connection to APNS every time you want to send notifications, not only because of the extra time it takes. I believe a better approach would be to have a different server (not running PHP) handle the stream writing to APNS and receive tokens and messages by let's say some kind of python service, perhaps.
Basically:
Web Server sends fwrite by php (unencrypted, no SSL) to a socket on a local server that has a persistent connection to APNS open, which also is asynchronous in its handling of the response from to the APNS operation: The problem is that PHP will wait until it has written all bytes to the socket before it echoes the desired response to the client. I would imagine it takes much less time to fwrite to a local server unencrypted than it does to SSL to APNS. Correct me if I'm wrong.
I don't have a lot of experience with Python, but as far as I know it's not that hard.
I have the tokens stored in MySQL and retrieving and generating the payload with PHP in place and working - it's just slowing everything down the way it's set up now.
I cannot find any guides on this subject - only how to do what I am already doing with fwrite and OpenSSL in PHP.
I seek suggestions as how to best handle this situation.

You don't need to switch to Python to solve this issue. What you could do is tweak your design a bit to resemble more of "dump and purge" concept.
Basically, the scripts that receive the GET and POST calls dump the data related to the push notification payload locally.
In the background, you have a PHP script running all the time that has already established a connection with APNS and just checks constantly if anything has been dumped locally and needs to be sent.
Script A (The dumper):
// ... something triggers a push ...
if ($_GET['something'] == 'foo') {
$data = // Get all data needed to build push
createPayload($data); // Dump data somewhere; file or database
}
// ... something else maybe ...
return; // Return asap to not keep client waiting
Script B (The purger):
$apns = // Open connection to Apple Push server
while (TRUE) {
// Read file or database where payloads get dumped
$success = (fwrite(payload to $apns));
sleep(5); // Sleep a bit to avoid CPU going crazy
if (!$success) {
// Reopen connection with Apple
}
}
// Close apns here in case you have a break condition in your loop
Using two scripts instead of one, you will return to your client as quickly as possible and still be able to send push notification quickly to Apple's servers.

Related

Passing a live socket between two PHP scripts

I'm writing a websocket server in PHP, that needs to be able to handle a large number of concurrent connections. I'm currently using the socket_select function to allow it to handle them, but this still blocks all other connections when sending a large block of data to a client. Is there a way for the master script to accept the incoming socket, and then start up a second PHP script (in a non-blocking fashion, obviously) and pass the client socket to that script for processing? I know this is possible in C, but the codebase is such that a migration is impossible, sadly.
*The server is running exclusively on a Unix stack, no need for a MS compatible solution.
I'm currently using the socket_select function to allow it to handle them, but this still blocks all other connections when sending a large block of data to a client.
Then don't send all the data at once. If you are going to do
socket_write ($mysocket, $mybuffer, 10000000);
then yeah, you'll have to wait until all 10 million bytes have been sent out. However, you can use the $write array of socket_select to check if you can write to the socket, in combination with non-blocking sockets. Each time socket_select says you have a 'go!' on the socket, write data until socket_write starts to complain (i.e. returns FALSE or less than the specified length). This will keep the socket's send buffer optimally filled.
The downside is that you must keep track of exactly where in your output buffer you are; also, turn off non-blocking on the socket after you've written al your data or socket_select will keep on firing (this assumes you want to send multiple large blobs of data).
The answer turns out to be the same answer you'd use in C - fork(). When you fork, the state of all open files and ports is preserved, so a child process can read a port that was opened by its parent (this is the same way that modern webservers spin off worker threads for each client connection that comes in) It does require using the pcntl (process control) module which is disabled by default and should be used sparingly, but it works:
if($verbose)
echo "Connected Client from $remoteaddy to $localaddy\n";
echo "Forking...";
$pid = pcntl_fork(); // you're bringing children into this world, just to kill them in a few seconds. You monster.
if($pid==0){
$p = posix.getpid();
echo "PID OF CHILD: $p\n";
//in child process. Send a handshake and wait for the callback from the WebSockets library
$this->send($client, "Thank you for contacting myAwesomeServer.com! I'm slave #{$p}, and I'll be your host today");
}else if($pid>0){
$childWorkers[]=$pid;
echo "[ OK ]\n";
$this->disconnect($client->socket, false); //disconnect the clients socket from the master thread, so only the child thread is talking to the client
}else if($pid==-1){
echo "[FAIL] unable to create child worker\n";
}
NOTE!! This approach is PURELY ACADEMIC, and should only be used on small, 'pet' projects when you don't have enough time to learn a more appropriate language (personally, I know C well enough to fork(), but my lack of knowledge of its string manipulation functions would no doubt leave a gaping security hole in the server). I'm not sure how the Zend engine is doing this pcntl_fork(), but I'd imagine that the memory image of this monstrosity is going to be many times the size of equivalent C code..

Server-sent events and php - what triggers events on the server?

All,
HTML5 Rocks has a nice beginner tutorial on Server-sent Events (SSE):
http://www.html5rocks.com/en/tutorials/eventsource/basics/
But, I don't understand an important concept - what triggers the event on the server that causes a message to be sent?
In other words - in the HTML5 example - the server simply sends a timestamp once:
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache'); // recommended to prevent caching of event data.
function sendMsg($id, $msg) {
echo "id: $id" . PHP_EOL;
echo "data: $msg" . PHP_EOL;
echo PHP_EOL;
ob_flush();
flush();
}
$serverTime = time();
sendMsg($serverTime, 'server time: ' . date("h:i:s", time()));
If I were building a practical example - e.g., a Facebook-style "wall" or a stock-ticker, in which the server would "push" a new message to the client every time some piece of data changes, how does that work?
In other words... Does the PHP script have a loop that runs continuously, checking for a change in the data, then sending a message every time it finds one? If so - how do you know when to end that process?
Or - does the PHP script simply send the message, then end (as appears to be the case in the HTML5Rocks example)? If so - how do you get continuous updates? Is the browser simply polling the PHP page at regular intervals? If so - how is that a "server-sent event"? How is this different from writing a setInterval function in JavaScript that uses AJAX to call a PHP page at a regular interval?
Sorry - this is probably an incredibly naive question. But none of the examples I've been able to find make this clear.
[UPDATE]
I think my question was poorly worded, so here's some clarification.
Let's say I have a web page that should display the most recent price of Apple's stock.
When the user first opens the page, the page creates an EventSource with the URL of my "stream."
var source = new EventSource('stream.php');
My question is this - how should "stream.php" work?
Like this? (pseudo-code):
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache'); // recommended to prevent caching of event data.
function sendMsg($msg) {
echo "data: $msg" . PHP_EOL;
echo PHP_EOL;
flush();
}
while (some condition) {
// check whether Apple's stock price has changed
// e.g., by querying a database, or calling a web service
// if it HAS changed, sendMsg with new price to client
// otherwise, do nothing (until next loop)
sleep (n) // wait n seconds until checking again
}
?>
In other words - does "stream.php" stay open as long as the client is "connected" to it?
If so - does that mean that you have as many threads running stream.php as you have concurrent users? If so - is that remotely feasible, or an appropriate way to build an application? And how do you know when you can END an instance of stream.php?
My naive impression is that, if this is the case, PHP isn't a suitable technology for this kind of server. But all of the demos I've seen so far imply that PHP is just fine for this, which is why I'm so confused...
"...does "stream.php" stay open as long as the client is "connected"
to it?"
Yes, and your pseudo-code is a reasonable approach.
"And how do you know when you can END an instance of stream.php?"
In the most typical case, this happens when the user leaves your site. (Apache recognizes the closed socket, and kills the PHP instance.) The main time you might close the socket from the server-side is if you know there is going to be no data for a while; the last message you send the client is to tell them to come back at a certain time. E.g. in your stock-streaming case, you could close the connection at 8pm, and tell clients to come back in 8 hours (assuming NASDAQ is open for quotes from 4am to 8pm). Friday evening you tell them to come back Monday morning. (I have an upcoming book on SSE, and dedicate a couple of sections on this subject.)
"...if this is the case, PHP isn't a suitable technology for this kind
of server. But all of the demos I've seen so far imply that PHP is
just fine for this, which is why I'm so confused..."
Well, people argue that PHP isn't a suitable technology for normal web sites, and they are right: you could do it with far less memory and CPU cycles if you replaced your whole LAMP stack with C++. However, despite this, PHP powers most of the sites out there just fine. It is a very productive language for web work, due to a combination of a familiar C-like syntax and so many libraries, and a comforting one for managers as plenty of PHP programmers to hire, plenty of books and other resources, and some large use-cases (e.g. Facebook and Wikipedia). Those are basically the same reasons you might choose PHP as your streaming technology.
The typical setup is not going to be one connection to NASDAQ per PHP-instance. Instead you are going to have another process with a single connection to the NASDAQ, or perhaps a single connection from each machine in your cluster to the NASDAQ. That then pushes the prices into either a SQL/NoSQL server, or into shared memory. Then PHP just polls that shared memory (or database), and pushes the data out. Or, have a data-gathering server, and each PHP instance opens a socket connection to that server. The data-gathering server pushes out updates to each of its PHP clients, as it receives them, and they in turn push out that data to their client.
The main scalability issue with using Apache+PHP for streaming is the memory for each Apache process. When you reach the memory limit of the hardware, make the business decision to add another machine to the cluster, or cut Apache out of the loop, and write a dedicated HTTP server. The latter can be done in PHP so all your existing knowledge and code can be re-used, or you can rewrite the whole application in another language. The pure developer in me would write a dedicated, streamlined HTTP server in C++. The manager in me would add another box.
Server-sent events are for realtime update from the server-side to the client-side. In the first example, the connection from the server isn't kept and the client tries to connect again every 3 seconds and makes server-sent events no difference to ajax polling.
So, to make the connection persist, you need to wrap your code in a loop and check for updates constantly.
PHP is thread-based and more connected users will make the server run out of resources. This can be solved by controlling the script execution time and end the script when it exceed an amount of time (i.e. 10mins). The EventSource API will automatically connect again so the delay is in a acceptable range.
Also, check out my PHP library for Server-sent events, you can understand more about how to do server-sent events in PHP and make it easier to code.
I have notice that the sse techink sends every couple of delay data to the client (somtething like reversing the pooling data techink from client page e.x. Ajax pooling data.) so to overcome this problem i made this at a sseServer.php page :
<?php
session_start();
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache'); // recommended to prevent caching of event data
require 'sse.php';
if ($_POST['message'] != ""){
$_SESSION['message'] = $_POST['message'];
$_SESSION['serverTime'] = time();
}
sendMsg($_SESSION['serverTime'], $_SESSION['message'] );
?>
and the sse.php is :
<?php
function sendMsg($id, $msg) {
echo "id: $id" . PHP_EOL;
echo "data: $msg" . PHP_EOL;
echo PHP_EOL;
ob_flush();
flush();
}
?>
Notice that at the sseSerer.php i start a session and using a session variable! to overcome the problem.
Also i call the sseServer.php via Ajax (posting and set value to variable message) every time that i want to "update" message.
Now at the jQuery (javascript) i do something like that :
1st) i declare a global variable var timeStamp=0;
2nd) i use the next algorithm :
if(typeof(EventSource)!=="undefined"){
var source=new EventSource("sseServer.php");
source.onmessage=function(event)
if ((timeStamp!=event.lastEventId) && (timeStamp!=0)){
/* this is initialization */
timeStamp=event.lastEventId;
$.notify("Please refresh "+event.data, "info");
} else {
if (timeStamp==0){
timeStamp=event.lastEventId;
}
} /* fi */
} else {
document.getElementById("result").innerHTML="Sorry, your browser does not support server-sent events...";
} /* fi */
At the line of : $.notify("Please refresh "+event.data, "info");
is there that you can handle the message.
For my case i used to send an jQuery notify.
You may use POSIX PIPES or a DB Table instead to pass the "message" via POST since the sseServer.php does something like an "infinite loop".
My problem at the time is that the above code DOES NOT SENDS THE "message" to all clients but only to the pair (client that called the sseServer.php works as individual to every pair) so i'll change the technik and to a DB update from the page that i want to trigger the "message" and then the sseServer.php instead to get the message via POST it will get it from DB table.
I hope that i have help!
This is really a structural question about your application. Real-time events are something that you want to think about from the beginning, so you can design your application around it. If you have written an application that just runs a bunch of random mysql(i)_query methods using string queries and doesn't pass them through any sort of intermediary, then many times you won't have a choice but to either rewrite much of your application, or do constant server-side polling.
If, however, you manage your entities as objects and pass them through some sort of intermediary class, you can hook into that process. Look at this example:
<?php
class MyQueryManager {
public function find($myObject, $objectId) {
// Issue a select query against the database to get this object
}
public function save($myObject) {
// Issue a query that saves the object to the database
// Fire a new "save" event for the type of object passed to this method
}
public function delete($myObject) {
// Fire a "delete" event for the type of object
}
}
In your application, when you're ready to save:
<?php
$someObject = $queryManager->find("MyObjectName", 1);
$someObject->setDateTimeUpdated(time());
$queryManager->save($someObject);
This is not the most graceful example but it should serve as a decent building block. You can hook into your actual persistence layer to handle triggering these events. Then you get them immediately (as real-time as it can get) without hammering your server (since you have no need to constantly query your database and see if things changed).
You obviously won't catch manual changes to the database this way - but if you're doing anything manually to your database with any frequency, you should either:
Fix the problem that requires you to have to make a manual change
Build a tool to expedite the process, and fire these events
Basically, PHP is not suitable techonology for this sort of things.
Yes you can make it work, but it will be a disaster on highload. We run stockservers that send stock-change signals via websockets to dozens thousends users - and If we'd use php for that... Well, we could, but those homemade cycles - is just a nightmare. Every single connection will make a separate process on server or you have to handle connections from some sort of database.
Simply use nodejs and socket.io. It will let you easily start and have a running server in couple days. Nodejs has own limitations also, but for websockets (and SSE) connections now its the most powerfull technology.
And also - SSE is not that good as it seems. The only advantage to websockets - is that packets are being gzipped natively (ws is not gzipped), but on the downside is that SSE is one-side connection. You user, if he wants to add another stock symbol to subscripton, will have to make ajax request (including all troubles with origin control and the request will be slow). In websockets client and sever communicate both ways in one single opened connection, so if user sends a trading signal or subscribes to quote, he just send a string in already opened connection. And it's fast.

How to communicate between concurrent sessions in PHP ans JS?

I have PHP server, in which I need to update client A about some client B action, at the moment it's done. How it is normally being accomplished ?
My current solution would be:
A leaves an open $.ajax(...).done(function myCallBack(){...}); call for this.
when A is in myCallBack(){...} it issues another $.ajax(...).done(function myCallBack(){...});. This way the communication with server stays open for receiving new info anytime
the PHP would have to continually check for inter-session communication file to transfer data to/from two concurrent sessions
Leaving $.ajax(...).done(function myCallBack(){...}); open (and spawning new ones all the time) is the way to do it ?
For inter-session communication - is there a way to signal events or something like that (instead of continuously monitoring some file [a waste of resources!]) ?
This is how I solved it:
Client A leaves an open ajax call: $.ajax(...).done(function myCallBack(){...});: on the PHP server side (session), A locks on a semaphore using sem_acquire($semaphore_A), and waits.
Client B removes semaphore $semaphore_A using sem_remove($semaphore_A), thus releasing A that returns to client JS callback myCallBack().
Of-course, it's very simplistic, and I use shared-memory (e.g. shm_attach()) to exchange status and data between processes.
For other developers stuck with this technique:
what took me so long to debug it, is the fact the I opened a session (session_start()) and didn't close it (session_ write_ close()) - which locked other processes and prevented any concurrency !
Client A would send data to the server, Client B needs to poll the server to ask for changes. When there are changes Client B would get them on it's next poll.

PHP socket_read returns empty string

I wrote a PHP class for a websocket client that allows you to connect to websocket servers from PHP. It works very well, except that it can only read data in an infinite loop. In a websocket connection, the server or the client can send data whenever they want, as many times as they want. Unfortunately, socket_select, socket_read, and socket_recv won't block if any data has been sent by the other socket - socket_select will return immediately, and socket_read and socket_recv will return an empty string. I tried making the process sleep until it received SIGPOLL, but that caused it to sleep indefinitely. Is there any way to know more data is available on the socket after data has already been received?
PHP is not a good language to go forth with this as it is not an asynchronous language. I would suggest Node.js or something similar.
I may not know much about PHP and websockets, but couldn't you just loop it until you hit SIGPOLL?

How to deal with streaming data in PHP?

There is a family of methods (birddog, shadow, and follow)in the Twitter API that opens a (mostly) permanent connection and allows you to follow many users. I've run the sample connection code with cURL in bash, and it works nicely: when a user I specify writes a tweet, I get a stream of XML in my console.
My question is: how can I access data with PHP that isn't returned as a direct function call, but is streamed? This data arrives sporadically and unpredictably, and it's not something I've ever dealt with nor do I know where to begin looking for answers. Any advice and descriptions of libraries or pitfalls would be appreciated.
fopen and fgets
<?php
$sock = fopen('http://domain.tld/path/to/file', 'r');
$data = null;
while(($data = fgets($sock)) == TRUE)
{
echo $data;
}
fclose($sock);
This is by no means great (or even good) code but it should provide the functionality you need. You will need to add error handling and data parsing among other things.
I'm pretty sure that your script will time out after ~30 seconds of listening for data on the stream. Even if it doesn't, once you get a significant server load, the sheer number of open and listening connections will bring the server to it's knees.
I would suggest you take a look at an AJAX solution that makes a call to a script that just stores a Queue of messages. I'm not sure how the Twitter API works exactly though, so I'm not sure if you can have a script run when requested to get all the tweets, or if you have to have some sort of daemon append the tweets to a Queue that PHP can read and pass back via your AJAX call.
There are libraries for this these days that make things much easier (and handle the tricky bits like reconnections, socket handling, TCP backoff, etc), ie:
http://code.google.com/p/phirehose/
I would suggest looking into using AJAX. Im not a PHP developer, but I would think that you could wire up an AJAX call to the API and update your web page.
Phirehose is definitely the way to go:
http://code.google.com/p/phirehose/

Categories