A friend of mine, who lectures at a university, was wondering about getting his students to submit a vote on the outcome of a debate in the days following the lecture. He was wondering about using Twitter for this – in the end he ditched the idea as not all of the class twitterererered.
Anyway – I’d been wanting to play with the Twitter Search API for sometime and this seemed like a good exercise.
I imagined the students being asked to tweet their votes using a unique keyword, e.g. mmu_geog_msc_07082012, followed by a ‘yes’ or a ‘no’. The state of the voting could then be checked using a simple page which calls the Twitter Search API with the unique keyword. Once the response has been received the data can be parsed and the positive/negative votes counted. See the screenshot below:
At first I planned to use AJAX and have the XMLHttpRequest call the Twitter Search API. Basically the javascript looked like the following:
//Gets the browser specific XmlHttpRequest Object function getXmlHttpRequestObject() { if (window.XMLHttpRequest) { return new XMLHttpRequest(); } else if(window.ActiveXObject) { return new ActiveXObject("Microsoft.XMLHTTP"); } } //Get our browser specific XmlHttpRequest object. var receiveReq = getXmlHttpRequestObject();
And then, in the open method, of the XmlHttpRequest object do something like this:
receiveReq.open("GET", 'http://search.twitter.com/search.json?q=mmu_geog_msc_07082012&rpp=100', true);
Note: it’s an interesting exercise, when initially using the Twitter Search API, to construct some simple requests and run them in the browser. e.g.
http://search.twitter.com/search.json?q=gis&rpp=100
I was then hoping to parse the returned JSON data (I don’t think it matters that object is called XMLHttpRequest) and count the vote keywords.
However, this isn’t possible because the XMLHttpRequest object doesn’t allow cross domain calls. Basically it means I can’t directly request pages on twitter.com if my calling page is on gt140.co.uk.
Twitter does allow JSONP requests to avoid this problem. This allows the caller to request a callback function. The response from twitter then wraps the data in the callback function which gets executed on return. It’s described in this article – worth a read. In the end I abandoned this approach as I couldn’t quickly see a way of making it work with a button. I did start reading that this would be easier if I used jQuery but I kind of liked the idea of doing things in just javascript – I really wanted to understand what was going on at a basic level.
So Plan C was to have the XMLHttpRequest object request an intermediate php page (residing on gt140.co.uk i.e. the same domain) which would call the Twitter Search API.
The php page on the server would use the cURL extension. This was something that wasn’t enabled by default for the php installation on my localhost (XAMPP) but it was on the host that I use for gt140.
Whether or not the cURL extension is enabled or not can be determined by creating and calling the following php file:
<?php echo phpinfo(); ?>
If curl is enabled the resulting page should have details related to the extension in a curl section.
In order to enable it on the localhost I simply had to locate the php.ini file (xammp\php\php.ini) and remove the semi colon (uncomment) from the following entry:
;extension=php_curl.dll
I confirmed it was enabled by re-loading the php info file.
I then constructed a simple main page (twitter_vote_thingy.html). This main page has a form which contains:
a. an input field through which the user can enter the unique keyword by which the voters identify their tweets (votes).
b. input fields through which the user can enter the words used for yes / no.
c. a button which when pressed uses the Twitter Search API to count the votes.
d. a table with some span elements for displaying the results. The span elements have identifiers.
When the button is clicked a javascript function is called (onclick=”countVotes()”). The countVotes function uses the XMLHttpRequest object to call a php page (countvotes.php). The onreadystatechange property of the object is set to a function which is called when the votes have been received (gotVotes).
The php page (countvotes.php) creates an instance of a php class (twitter.class.php) and calls it’s method (countTweets). This is done without reloading the page. countTweets uses curl to search for tweets containing the unique keyword using the Twitter Search API. The final calls looked something like this after the variable containing the unique identifier has been substituted:
http://search.twitter.com/search.atom?q=mmu_geog_msc_07082012&rpp=100
The countTweets method receives an Atom response from the API (note: I switched to Atom as I’ll be documenting some future mini-adventures using xml responses), parses the results and counts the positive votes, the negative votes and the spoilt papers (i.e. tweets containing the identifier keyword but no vote keyword). It then returns these as a comma seperated string. countvotes.php receives the comma seperated string and echos it back.
This is then picked up in the main page by our onreadystatechange function (gotVotes). gotVotes parses the string and updates the display fields on the main page accordingly.
Finally I used a bit of CSS to give the main page a neat and tidy look.
Source code is here.
Try it out here.
In order to carry out this mini-adventure I found the following resources really useful:
Twiter Search API docs – goes without saying really.
http://www.dynamicajax.com/fr/AJAX_Hello_World-.html – simple introduction into AJAX.
http://www.w3schools.com/ajax/ajax_aspphp.asp – another simple explanation of AJAX.
http://www.richnetapps.com/php-twitter-search-parser/ – a twitter parser by Armand Niculescu which was a good reference for my parser.