Push Notifications with Prowl
Push notifications to mobile devices are a quick and inexpensive way to send short messages to people wherever they happen to be – provided their phone is switched on, of course. But to send a notification, there are usually a number of hoops you to jump through; not least, registering your device so that the sending service can target your phone. This is understandable, of course, as there is enormous potential for misuse.
Suppose, however, you want a quick and easy way to send messages to yourself or a select group of people without having to register an application with Apple and play around with various certificates and processes. You might be interested in learning about Prowl.
Prowl is an iOS-based Growl client, the short messaging system that’s popular on Apple Macs. You can purchase a copy for your phone and “hook it up” to all sorts of services and applications – and perhaps most intriguingly, use its API to send messages from your own applications. That’s what we’ll look at in this article.
Getting Started
The first thing you’ll need is the Prowl application on your iOS device. You can download it from the App Store, and at the time of this writing it costs $2.99 USD.
Next, you’ll need to create an account on the Prowl website. Once you’re registered, you can create API keys. An API key is an identifier used to target devices registered with your account. You can set up multiple API keys for different uses, but you’ll only need one for now. All you need to know is that if you send a message targeted at one API key, you’ll receive it on all the devices registered with your account.
You also need to associate your copy of Prowl with your account. Open the app on your iOS device and enter the login information you provided when you registered with the Prowl website.
With everything set up, let’s test it. Log in to the Prowl website and go to “Add Message”. Send a short message, which you should receive on your iOS device. You can also set the priority of the message, as well as a URL which can be opened from the notification.
It’s worth noting that there are a number of other ways in which you can send messages. A number of applications for various platforms are listed on the Prowl site, some of which are even web apps (like the Prowl Chrome Extension which allows you to send your current URL to your device straight from the browser). You may also have noticed that an email address is generated when you add an API key in the form of <api_key>@api.prowlapp.com. If you send mail to that address, you’ll receive it as a push notification via Prowl.
Because the process of creating an API key is a bit convoluted, and the key’s format is not user-friendly, Prowl might not be the ideal choice for public applications. It’s one thing to ask someone who’s not particularly tech-savvy to enter an e-mail address or mobile number, but quite another to expect him to generate a key, then copy and paste it in a form. But if you’re sending messages to yourself, or perhaps a small team, that process probably isn’t too much of a concern.
Also, the Prowl API has a rate limit – arguably a rather generous one – 1,000 calls per hour per IP address. If you require more than this, you can create a provider (from the API keys page) and use that in your API calls.
Assuming all is well and you are receiving messages, we can move on to the next section.
Building Your Own Applications
This is where things gets interesting – using Prowl’s API to send messages from a PHP application! We’re going to use ProwlPHP, a PHP library to interface with the API – but if you want to get your hands dirty and explore the API yourself, refer to online documentation. The library is available on GitHub and Composer.
{
"require": {
"xenji/ProwlPHP": ">=1.0.2"
}
}
To send a message, you first need to instantiate the Prowl connector, optionally set a provider key, and tell the connector you’re going to make a POST request:
$prowl = new Prowl\Connector();
$prowl->setProviderKey('YOUR-PROVIDER-KEY');
$prowl->setIsPostRequest(true);
Next, you are required to add a filter. You can use a closure to define a filter for the message text, for example to sanitize user input, limit the amount of text, appending extra information, and so on.
$prowl->setFilterCallback(function ($text) {
// ... do something
return $text;
});
Alternatively, you can create a filter in a more object-oriented fashion by extending ProwlSecurityPassthroughFilterImpl
and implement its filter()
method:
class CustomFilter extends ProwlSecurityPassthroughFilterImpl
{
public function filter($sContentToFilter) {
// Do something
return $sContentToFilter;
}
}
$filter = new CustomFilter();
$prowl->setFilter($filter);
Now create an instance of ProwlMessage
:
$msg = new ProwlMessage();
$msg->setApplication('My Prowl Application');
$msg->addApiKey('YOUR-API-KEY');
$msg->setPriority(0);
$msg->setEvent($event);
$msg->setDescription($description);
$msg->setUrl($url);
The addApiKey()
method is where you specify the recipient; you can call this multiple times to send the message to multiple recipients.
The priority given to setPriority()
should be one of the following values:
The setEvent()
method sets the name of the event, and can be up to 1,024 characters. Additionally, you can set an optional description for the event with setDescription()
, and an optional URL, which can be opened directly from the notification, with setUrl()
.
Finally, to actually send the message, call the push()
method:
$response = $prowl->push($msg);
Application Logging using Prowl
Let’s say you’ve built a web application which is used by a significant number of people. What happens when a critical error occurs? You probably have logging set up, and perhaps the messages are logged to a file, a database, or some sort of datastore like Redis, but you’re going to want to know about serious errors straight away. What better way then by sending a push notification!
Many logging implementations provide the ability to define a number of log writers and configure them to respond to different error levels. For example, you may wish to log informational messages to a file but send critical messages by email. Zend_Log is one such implementation. Although it’s technically part of Zend Framework, it can also be used in a standalone fashion provided you make its dependencies available to your application. You can download it from the Zend Framework website or install it using Composer.
{
"require": {
"zendframework/zend-log": "2.2.*",
"xenji/ProwlPHP": ">=1.0.2"
}
}
Let’s create our own implementation of Zend\Log\AbstractWriter
to send certain log messages via Prowl. The class will need to:
- have a property to store the Prowl keys
- accept the keys via its constructor
- implement the
doWrite()
method
namespace SitePoint\Log\Writer;
use Zend\Log;
class Prowl extends \Zend\Log\Writer\AbstractWriter
{
private $apiKeys;
public function __construct($apiKeys) {
if (is_array($apiKeys)) {
$this->apiKeys = $apiKeys;
}
else {
$this->apiKeys = array($apiKeys);
}
$this->_formatter = new Log\Formatter\Simple('%message%');
}
protected function doWrite(array $event) {
$event = $this->_formatter->format($event);
$prowl = new \Prowl\Connector();
$prowl->setFilterCallback(function ($text) {
return $text;
});
$prowl->setIsPostRequest(true);
$msg = new \Prowl\Message();
$msg->setApplication('My Custom Logger');
$msg->setPriority(2);
$msg->setEvent($event);
foreach ($this->apiKeys as $key) {
$msg->addApiKey($key);
}
$prowl->push($msg);
}
A few notes about the class:
- I set the formatter in the constructor which will simply send the message as-is. You can set this to any format you wish, or override it later.
- I’m doing everything – e.g. instantiating the connector – in the
doWrite()
method to keep things simple. You may wish to expand the constructor to accept the application name, a provider key, etc. - I’ve hard-coding the priority as 2 – emergency – however, you may want to map the log priority to the Prowl priority, bearing in mind how few of the latter there are (and you’re probably only going to use Prowl for critical messages anyway).
Finally, registering the writer with the logger looks like this:
$apiKeys = array(
'YOUR-API-KEY',
'ANOTHER-API-KEY'
);
$logger = new Zend\Log\Logger();
$writer = new SitePoint\Log\Writer\Prowl($apiKeys);
$writer->addFilter(
new Zend\Log\Filter\Priority(Zend\Log\Logger::CRIT)
);
$logger->addWriter($writer);
Conclusion
In this article, I’ve shown how you can send ad-hoc push notifications to yourself or others using Prowl. I’ve demonstrated sending critical log messages direct to your mobile phone, and there are all sorts of things you can use Prowl notifications for. Here are some more examples:
- Multi-factor authentication
- New email or comment notifications
- Group messaging
- Security alerts (e.g. intrusion detection)
Perhaps you can think of more? Let me know in the comments below!