Back to Home

One PHP API for all cloud push services

push · pusher · pubnub · partcl · PHP · Comet · real-time · push cloud

One PHP API for all cloud push services

    Greetings to all readers. There are so many trends in web development that you can’t follow. But the question of real-time interaction with users of the site is an acute read for any project. The easiest way is to put one of the widely available open comet-servers, for example, Dklab_Realplexor, Socket.IO or Faye - which is to your liking or depending on the technology stack. True, this is the path of quite complex projects where the team can afford such a solution.

    For many projects, it’s simpler (although this is always a matter of application specificity) it will be logical to use third-party solutions. And it’s easier to rent comet-server functionality as a service. Today there is no shortage of such services, so we have something to review.

    And so, first, let's briefly look at the existing push services that will allow us to maintain real-time communication between project clients without creating and supporting our server infrastructure.

    There are only 6 such services: Pusher , Pubnub , Partcl , BeaconPush , X-Stream.ly and ioBridge (with some features). Under the cut is a brief overview of all services, the features of PHP libraries for them and a description of the pushBridge.IO library to unify work with all cloud push services.

    Pusher.com

    The most famous of these services. At the same time, it is one of the most difficult because of the abundance of opportunities. In general terms, communication is divided into channels, within which there are user events that client code subscribes to (javascript). In addition, there are a number of system events, as well as a system of statuses and alerts and connections / disconnections of other channel users. It is possible to work with private channels, so that even a connected user, but not knowing the code identifier, will not receive events.

    To interact with other systems, Pusher uses the REST-HTTP-API (however, like all similar services), and provides a number of ready-made libraries for 11 languages, including Clojure, Groovy and ColdFusion. I was only interested in the PHP API, which is represented by 4 plugins - for Kohana, Code Igniter and a bundle for Simfony 2 frameworks, as well as one independent class ( http://github.com/squeeks/Pusher-PHP ). To work, it requires the extension cURL and json, as well as sha256 as a hash algorithm.

    As a note, I’ll say that it was from this service that the idea of ​​my library came about. I will be honest - for one project I needed real time, but I didn’t want to write my server in the test version, so in a couple of minutes I thought about connecting a pusher, especially since I already had an account. it turned out that with all the advantages and abundance of documentation, the system is not so simple, and not all moments are well-painted there. the debug mode helped a lot when on the site in the console section all your requests sent via the API are displayed in real time. But somewhere I set foot and although requests were sent, they did not reach the client. At this point, after an hour of debugging, I abandoned this thing. I did not like the prospect of rewriting the code again, and besides, in the final version of my project, I would still have to switch to my own server. So the idea came up - why do you need to rewrite everything every time, if you can try to reduce everything into one unified interface. Looking ahead, I will say that the idea has successfully found its implementation!

    PubNub.com

    This service is simpler and, in this, I see its advantage. The API is extremely simple - there are channels, messages in them and that’s it. The data format, of course, is everywhere JSON. Both on the client side and on the server side, Pubnub has the widest coverage, providing access to the service on any platform and programming language. The simplicity and powerful support of all platforms makes this service the most interesting of those considered, especially if you need to provide real time everywhere.

    The PHP library for accessing the service is quite simple, it allows both sending and receiving messages based on cURL. It works on both 5.2 and 5.3 versions of PHP; I allow using buns like callback functions. After studying the source code, the big question remained - for some reason, when sending, after converting to JSON, the message length should not exceed 1800 characters! What is the reason for this limitation is not yet clear, I will contact the developers and find out.

    Partcl.com

    A fairly new service in this market, initially focused on embedding real-time updated tags on a web page. Currently, the API is quite expanded there and allows you to get a history of changes in values, build graphs that also work in real time, etc. Unlike other services, positioned only as communication, Partcl also works as a content provider, storing all messages and data, which is a rather unique function. Revealing some details, I will say that the server part is written in Node.JS + Redis (it’s the real time “distributor” - I’m its immediate developer), and the web part is on the Zend Framework.

    Although the PHP API was already written for the system, and even a plugin for integration into Wordpress, it was, by my standards, quite primitive and might not work on some hosting services. So I also tried writing a new library implementation for partcl. It turned out even better than the original.

    BeaconPush.com

    A little-known service, but the only one that offers a dedicated server for demanding clients (the system, by the way, is written in Java). And so, it is ordinary, although in addition to channels and messages, it also brings up the user's abstraction, simplifying communication between specific connected clients. In addition, there is an interesting functionality of web hooks when the service itself pulls the URL you specified, signaling about users entering / exiting the channel. It is also possible to control the publication capabilities - if you do not enable it, anyone who knows the public id will be able to publish data, otherwise only having a secret key.

    But with the PHP API, this service did not work out in any way. He certainly is ( https://github.com/ImDom/BeaconPush-PHPand even a module for Code Igniter), but the quality ... is very far from good. By the way, the author of the module sewed his account into the source. Honestly trying to use a ready-made module, but could not configure it to work correctly (stupidly refused to accept my account id), I completely rewrote its API under Zend_Http.

    X-Stream.ly

    Another almost unknown service, however, which has a number of interesting features. For example, you can create keys specifically for regulating the access of specific users to the API (apparently due to the business model). Also, it is the only one, except for Partcl, that has the functionality of permanent message storage. Other features are more or less standard - channels, events, private channels with password access, user statuses. A unique feature is the twitter feed, when the service itself will connect to the specified Twitter account and broadcast new messages to all connected users. On the event of a message appearing in the channel, you can put callbacks, which can also be controlled via the REST-API. By the way, this service is the only one that, in order to publish (and generally, access) to its HTTP API, in addition to the id and secret key, requires HTTP authentication,

    The server’s native server API is more than meager - C #, Ruby, and Node.JS. I had to implement part of their API from scratch, so here I am the first to write a library.

    ioBridge.com

    The most interesting and strange service, not even push. It is focused on connecting all kinds of glands to the web (controllers and boards), and also provides data display, collection and storage, and web-based management. There is also no native client on PHP, in the official forum there are several suggestions and drafts of the code, but they are far from a quality implementation. Yes, and I understood why, starting to do it myself - the service is very strange in places, for example, to get the actionId of the widget and session id, you need to make a request to their server, which immediately returns a piece of HTML + JavaScript, from which you have to fetch data using stupid parsing of strings , which are then needed to connect and send commands. Unfortunately, I couldn’t move beyond the basic code, apparently, for the full testing, I need to connect the device itself.

    And now about the most important thing - pushBridge.IO PHP Library



    My library for PHP is designed to replace all the native libraries for access to each of these services, provides a single and common interface to the basic functionality, while maintaining the ability to work directly with the original library (for those cases when it is). For some services, this is the first or, not shame, the best library (at least in PHP).

    So far, only the basic functionality has been implemented - connecting and authorizing where required, and sending a message to the specified channel or generating a user event. All other specific functions can be obtained directly from an instance of the connection class. In the next version, it will also be rewritten so as not to depend on foreign libraries and provide a single interface for all operations (getting the number of connected users, message history, reading messages, etc.).

    The library is divided into two parts - the base class is responsible for initializing the desired adapter, processes the message, and, if necessary, serializes it. For this, I used the Zend_Serializer class, so all its formats are supported - from regular Json to exotic Wddx.

    The adapter class is responsible for working with specific services, which, if necessary, connects the native library. So far, native classes are used only for Pusher and PubNub, due to the fact that services provide their own specific functions that have not yet been ported. But after initialization, you can always continue to work directly by simply calling the getConnection () method.

    I also tried to somehow unify the data for authorization. Some services use app_id and a secret key, others call them publish and subscribe / public keys, etc. Therefore, I tried to reduce them to a minimum set and keep one name for all services:
    • appId - this is usually an application id or API key, a unique identifier for an account or application
    • authKey - secret key that gives the right to publish data
    • secretKey - password or other secret key to access your account
    • readKey - public key for connecting as a client and reading data
    • emailKey - user login in the form of e-mail (so far this is exclusively for x-Stream.ly)


    To work with the library, three lines are enough:

    1. Initialization and connection.


    $push = new pushBridge_IO( [ Adapter ], [serializer] );

    The first parameter is the adapter instance for the service you need, for example: Usually, only authorization data is sufficient, the set of which is specific to the service. But the library, unlike the native classes, allows flexible control of connection methods using the network stack from Zend_Http. For requests, you can use cURL, directly sockets or an adapter for working through a proxy. By default, cURL is used, but if you need, pass the adapter name as the httpAdapter parameter, and any settings for it according to the ZF documentation in the httpAdapterConfig, for example, here . I confess that at this point there is still a bug in the current library implementation, while the options set by the user for the adapter are not used, this will be fixed in the next version (the other day).

    new pushBridge_Adapter_Pusher(Array('appId' => 'Your app Id', 'authKey' => 'Your key', 'secretKey' => 'Your secret key', 'debug' => true));





    Since different services require (or vice versa) different methods, you can specify in the method parameter how the adapter will connect to the server. This is usually GET, but sometimes services understand only POST. The adapter takes this into account, but you can override this parameter.

    The library inserts its custom header into the request, X-Powered-By, identifying itself, if desired, this can be turned off to save network traffic or simply out of principle.

    The second parameter is the serializer that will process the message. All services accept either JSON, or (some, for example, Partcl) just a string, without conversion. Initially, there is json using the Zend_Serializer class, however you can override it with any other. It is enough to pass as a second parameter either a string with the name of the serializer (now we support: json, php and pickle) or immediately an instance of the Zend_Serializer class with the options you need.

    Examples:

    Partcl:
    $push = new pushBridge_IO( new pushBridge_Adapter_Partcl(Array('secretKey' => 'Your secret key')) );
    Pusher:
    $push = new pushBridge_IO( new pushBridge_Adapter_Pusher(Array('appId' => 'Your app Id', 'authKey' => 'Your key', 'secretKey' => 'Your secret key', 'debug' => true)) );
    Pubnub:
    $push = new pushBridge_IO( new pushBridge_Adapter_Pubnub(Array('readKey' => 'Your subscribe key', 'authKey' => 'Your publish key', 'secretKey' => ' Your secret key')) );
    BeaconPush:
    $push = new pushBridge_IO( new pushBridge_Adapter_Beaconpush(Array('authKey' => 'Your API Key', 'secretKey' => 'Your secret key')) );
    And for example with a custom serializer:
    $push = new pushBridge_IO( new pushBridge_Adapter_Partcl(Array('secretKey' => ' Your secret key')), ‘php’ );
    or
    $push = new pushBridge_IO( new pushBridge_Adapter_Partcl(Array('secretKey' => 'Your secret key')), Zend_Serializer::factory('Wddx', Array(‘comment’ => ‘Powered by ZF+pushBridge.IO’) );

    2. Just send a message.


    In fact, everything is not so simple. Services work very differently with messaging. The simplest is the channel-> message model (or tag -> message), while others introduce a new level - channel -> event -> message. In this case, only partcl is very tolerant of the contents of the message, for him it is just a line, and its understanding is completely transferred to the client. Others require special message wrapping in json structures. None of the services supports mass sending of messages, when in one request it would be possible to publish data in different channels or several different messages and events in one channel. We have already taken into account this moment, and in the next version of our Partcl.com service, such an opportunity will be, in parallel, an emulation of this functionality will appear in the library for everyone else (for the sake of justice,

    The general sending method looks like this:

    $push->send( 'сообщение', 'channel', 'config' );

    An already converted string gets into the adapter method, so it is guaranteed to receive data and it is something more than an empty string. However, if the service requires it, the adapter will form the necessary Json structure on top of the message data.

    If channels are used in the service, the second parameter is the string (or array) of channels where the message should be sent. if there are no channels, this is a tag id or another id.

    If you need to set the event code, use the config - the third parameter is always an array. The event is set in the event parameter. Additionally, you can disable serialization by passing the parameter serialize = false. If the service accepts, you can specify additional message parameters, for example, the save data flag for X-Stream.ly or enable / disable debug mode for messages in Pusher.

    An example of sending a simple message:

    Partcl:
    $push->send('Hello world from pushBridge.IO', 'Your tag id', Array('serialize' => false));
    Pusher:
    $push->send('Hello world from pushBridge.IO', 'test_channel', Array('serialize' => false, 'event' => 'push_test', ‘debug’ => true));
    Pubnub:
    $push->send('Hello world from pushBridge.IO', 'my_channel');
    x-Stream.ly:
    $push->send('Hello world from pushBridge.IO', 'mychannel', Array('event' => 'my_event', ‘persisted’ => true));

    Of course, by default, the maximum parameters are set so that there is no need to set something, often even the name of the channel or event is set as they are assigned by the service after registration. But for a more complete understanding of the options, you should refer to the documentation for a specific service.


    Library source code and short examples:github.com/aleksraiden/pushBridge.IO/tree/ServiceWrapper

    Plans for the next release: bug fixes, unification of the send method, support for publishing several variables at once, implementation of the data reading method, as well as raising the project site on the pushcloudapi.com domain. I would be grateful for the comments and additions.

    Read Next