The Campaign for a Bradley Renaissance: SMS and Drupal: Two Great Tastes That Taste Great Together!
This is the fourth in a series of posts chronicling the Campaign for a Bradley Renaissance kickoff gala, a mediated event in which I used Drupal to gather alumni memories and run a quiz show via SMS and display photography both on the small iPhone screen and on some giant screens via Flash.
As you'll recall from the last post, the idea of providing refurbished Nokia phones for all 120 of our tables just wasn’t going to work out. Flash Lite was too limited, Java was locked down, and the annoying modal popups triggered after using SMS or a data connection would destroy the experience, and so we turned our search to an SMS or MMS gateway.
There are several options out there for receiving text messages. You can get a GSM modem, put a SIM card in it and pull down all SMS messages sent to a certain number. This is certainly a cost-effective way to go about things, and it means that you can easily get a SIM set up for service on a local number. On the negative side, transmission speeds are pretty slow, taking several seconds per message, and the donors would have to type in a ten-digit number each time they wanted to interact with the system.
I then started researching SMS gateways. Commercial providers like Clickatell and Mobivity provide SMS gateways which take in SMS messages and then deliver them to your web application in a variety of ways. Most can email you, post a log file to a server via FTP, or even perform an HTTP POST or GET each time a message is received. I knew that I wanted to go with the last option because then I could test the gateway very easily by hand in a web browser, and I figured that would also be the path of least resistance into Drupal.
There was also the issue of deciding how donors would interact with the system. We could get a 10-digit phone number in our (309) area code, but then only users of GSM networks (mainly AT&T and T-Mobile stateside) would be able to send their text messages into the system. We realized that an SMS shortcode (a 5- or 6-digit number) would be the best option. The only problem is that shortcodes take around 60 days to set up, and we didn’t have that much time. Luckily, Clickatell agreed to give us a shared shortcode, where we would be given a shortcode and all of the messages would have to be prefixed with a keyword (in this case “BU”) in order to get to our system.
I'm going to break up this otherwise long and technical blog post with some footage from the event that Chris Faczek, one of our talented senior video students, put together. Notice that the interface in the lower-left of the quiz questions was live during the event, but is not in the video. Also, look at how hyped up people got over the game show!
I initially decided to use Clickatell’s SMS gateway for a number of reasons. First, Clickatell is a global provider (perhaps the biggest in the world,) and they had a number of services. Secondly, and perhaps most importantly, each of the two major SMS modules in Drupal supported Clickatell out of the box.
Using Clickatell’s HTTP option, each time an SMS message is received into their system, they will perform a POST or GET request to a given URL which would look like this assuming you had chosen http://www.example.com/sms.php as your HTTP endpoint: http://www.example.com/sms.php?api_id=API&from=FROM&to=CODE×tamp=20...
Thus, my first SMS script was born, which you can use to send an email each time you receive an SMS message.
<?php $timestamp = $_GET['timestamp']; $from = $_GET['from']; $text = $_GET['text']; $message = "You got a message from $from at $timestamp. They said: $text"; mail("test@example.com", "SMS Received from $from", $message); ?>
Rather than writing custom code to handle SMS messages, though, I decided to look at the two modules that already exist: the SMS Framework module and the SMS Gateway module. The SMS Framework module was a Google Summer of Code project, and it looked to have a lot more promise than SMS Gateway, but there’s one glaring issue: no official release. SMS Gateway, on the other hand, has a stable release and comes with a Clickatell driver. I installed the SMS Gateway module and started looking through the documentation.
The SMS Gateway module allows you to send messages via a pluggable gateway system for which Clickatell used to the be the only option – more on that later. It also provides a new hook for when messages are received, hook_smsgateway_newmessage().
There’s one more change that I had to make from my early, purely-PHP email tests. Whereas my first tests were contacting http://example.com/sms.php upon receipt of a text message, the Drupal path to receive messages through SMS Gateway is /smsgateway/in, so I set our Clickatell gateway to send new requests to http://example.com/smsgateway/in .
With that, I was ready to at least begin receiving SMS messages in Drupal by implementing the hook. I decided to rename the story content type to memory, since the Drupal site that I would use would not be public, and I decided not to create an extra content type just for memories, since they were essentially just SMS messages coming in, so the body text was all that mattered.
In addition, we’d need an approval cycle. This was a high-profile event, so we could not allow any nodes to be published without them being at least approved or edited.
Finally, I decided that each phone number should have its own unique user account. This would allow me to block troublesome users or contact a user if it appeared they were having trouble. With this in mind, I would have to do the following upon receiving a text message:
- Check if a user account for the phone number exists, and if not, create it.
- Make a new node with the body from the SMS message, and set it to unpublished.
I added this code into a custom module I wrote called the smsgateway_content module. I have not run this through the coder module, so I make no guarantees that it’s all up to Drupal coding standards. Nevertheless, here’s the two crucial functions that make the whole thing work:
function smsgateway_content_smsgateway_newmessage($message) { $account = _smsgateway_check_user($message['sender_number']); $message_text = trim($message['body']); // No nodes for blocked users. if (!user_is_blocked($account->name)) { $node_type = 'memory'; // Create a new node (adapted from <a href="http://api.drupal.org/api/function/drupal_execute/5" title="http://api.drupal.org/api/function/drupal_execute/5">http://api.drupal.org/api/function/drupal_execute/5</a>) $node = array('type' => $node_type); $values['title'] = sprintf('%s: %s', $message['sender_number'], $message['body']); $values['body'] = $message['body']; $values['name'] = $account->name; $values['name'] = $message['sender_number']; $values['status'] = 0; // Send it in unpublished! drupal_execute($node_type . '_node_form', $values, $node); db_query("UPDATE {node} SET uid=%d WHERE title='%s'", $account->uid, $values['title']); } } function _smsgateway_check_user($phone_number) { $user_criteria = array(); $user_criteria['name'] = $phone_number; $account = user_load($user_criteria); if ($account === FALSE) { $values['name'] = $phone_number; $values['mail'] = "$phone_number@teleflip.com"; $values['pass'] = user_password(); $values['status'] = 1; $account = user_save(null, $values); } return $account; }
That will create a new memory (formerly story) node each time a new SMS message is received in Drupal and set it to unpublished. With that, we've got the content in Drupal, associated with a user account, and ready to be displayed.
Finally, let's examine one line in particular from the implementation of hook_smsgateway_newmessage():
db_query("UPDATE {node} SET uid=%d WHERE title='%s'", $account->uid, $values['title']);
Whether I used drupal_execute() or node_submit() and node_save() to generate this new node, I could not get the uid to populate properly on these newly-created nodes, so this was my hackish way around it.
Be sure to check back for the next post in this series where I’ll take a look at the custom approval interface we built for our Drupal site and how we could start to send these memories into the Flash applications and only the giant 26-foot screens.

Did you try overcoming Flash
Did you try overcoming Flash Lite limitations with KuneriLite?
Ugur, The Nokia 6085
Ugur,
The Nokia 6085 GoPhones that we were using only had Flash Lite 2.0 (hence we couldn't use XMLSocket), and they are Series 40 phones. It does look like the options out there for the Symbian platform are far more diverse.