I wanted to build a simple module for the AOL AIM Pages site and I wanted to start with something really simple so why not turn the classic Unix fortune program into a service.
At first I figured I would just use an existing service but the only one I could find was written in SOAP and for me to parse that in javascript would take longer than writing a REST service from scratch.
So I dug around some PHP sites (not a language I normally use) and before long I had a simple service..
version 0.1
- This version supports 4 types of output
- XML
- javascript output via document.write
- javascript with fortune returned in a variable
- plain HTML output
- I read the unix.txt (or funny.txt) file and make some changes to support the javascript and XML output. (much of this is probably unnecessary since I am using CDATA)
- To keep load on the machine low and response time good, I used Richard Heyes' cache code to keep the formatted data in memory.
- Everytime someone hits the service they get a new fortune.
- To prevent quotes in the fortunes from messing up my javascript output I urlencoded all the data then had the resulting javascript unencode it when it was finished. There is probably an easier way to do this but I don't really know javascript.
<?php include("Cache.php"); $fileName = "unix.txt"; $category = ""; if (isset($_GET["category"])) $category = $_GET["category"]; switch ($category) { case "unix": $fileName = "unix.txt"; break; case "funny": $fileName = "funny.txt"; break; case "default": $fileName = "unix.txt"; break; } if (!$result = DataCache::Get("test123", $fileName)) { $result = array(); $lines = file($fileName); $current = ""; foreach ($lines as $line_num => $line) { if (strcmp(substr($line,0,1),'%') ==0) { $result[] = $current; $current = ""; } else { // escape & $tmp = str_replace("&", " &", substr($line,0, strlen($line))); // Preserve spaces $tmp = str_replace(" ", " ", substr($tmp,0, strlen($tmp))); // escape < $tmp = str_replace("<", " <", substr($tmp,0, strlen($tmp))); // escape > and replace line feed with br tag $tmp = str_replace(">", " >", substr($tmp,0, strlen($tmp)-1)). "<br />"; // add to current fortune $current .= $tmp; } } if (strlen($current) > 0 ) $result[] = $current; DataCache::Put("test123", $fileName, 6, $result); } // Do something useful with $result srand ((double) microtime() * 1000000); $randomquote = rand(0,count($result)-1); $format = ""; if (isset($_GET["format"])) $format = $_GET["format"]; // prevent caching header("Cache-Control: no-store"); header("Pragma: no-cache"); header("Expires: Thursday, 05-May-05 05:05:05 GMT"); switch ($format) { case "js": header("Content-type: text/plain"); echo "function fortune() {"; echo "document.write(\"<p>\");"; echo "document.write(unescape(\"" . rawurlencode($result[$randomquote]) . "\"));"; echo "document.write(\"</p>\");"; echo "}"; break; case "jsVar": header("Content-type: text/plain"); echo "var fortune=\"" . rawurlencode($result[$randomquote]) . "\";"; break; case "xml": header("Content-type: application/xml; charset=utf-8"); echo "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>"; echo "<fortune>"; echo "<![CDATA[" . $result[$randomquote] ."]]>"; echo "</fortune>"; break; default: header("Content-type: text/html"); echo $result[$randomquote] ; } ?>
Output types..
- http://tonycode.com/service/fortune-0.1/fortune.php?format=js
- Returns javascript that outputs the fortune via document.write (good for basic injection)
- http://tonycode.com/service/fortune-0.1/fortune.php?format=jsVar
- Returns the fortune in a javascript variable that needs to be unescaped (good for injection via innerHTML
- http://tonycode.com/service/fortune-0.1/fortune.php?format=xml
- Returns the fortune in xml format (good for xsl transformations)
- http://tonycode.com/service/fortune-0.1/fortune.php
- Returns the fortune as an html snippet (good for ajax)
To use the javascript you would src in http://tonycode.com/service/fortune-0.1/fortune.php?format=js in your javascript block and then call the fortune function.
On iamalpha.com my module manifest uses the jsVar format and looks like this..
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" > <head profile="http://iamalpha.com/.developer/profile"> <title>Fortune</title> <link href="Fortune.css" id="Fortune-css" rel="stylesheet" type="text/css"/> <script language="JavaScript1.1" src="http://tonycode.com/service/fortune-0.1/fortune.php?format=jsVar" type="text/javascript" ></script> <!-- defines initFortune() --> <script language="JavaScript1.1" type="text/javascript" src="Fortune.js"> </script> </head> <body id="Fortune" onload="initFortune()" > <h1>Fortune: Version <span>1.0</span></h1> <h2>View Interface</h2> <div> <div><h3>Random Quotes</h3></div> <div> <div id="fortuneDiv"> fortune goes here </div> <p> Fortune/version 0.1 <a href="http://www.tonycode.com/forum/"> suggestions? </a></p> </div> </div> <h3>Description</h3> <p>An implementation of Unix fortune</p> <h3>Detail</h3> <p>A simple module to display a fortune</p> <h3>License</h3> <p><a href="http://www.gnu.org/copyleft/lesser.html" rel="license">GNU Lesser </a>.</p> <h3>Author Information</h3> <ul> <li> <a href="mailto:whatever@tonycode.com">Tony Primerano</a> - <a href="http://tonycode.com/">Homepage</a></li> </ul> <h3>Module Properties</h3> <dl> <dt>Liquid width module?</dt> <dd>true</dd> <dt>Allow multiple module instances on a single page?</dt> <dd>false</dd> <dt>Module's default width (in pixels):</dt> <dd>0</dd> <dt>Module's minimum width (in pixels, please, see I asked nicely that time):</dt> <dd>100</dd> <dt>Thumbnail</dt> <dd><img alt="fortune cookie" src="Fortune.jpg"/></dd> </dl> </body></html>
initFortune is defined in the Fortune.js file that is delivered with the module. All it does is inject the fortune into the div with the fortuneDiv id.
function initFortune() { document.getElementById("fortuneDiv").innerHTML=unescape(fortune); }
See this module and others on my page http://www.aimpages.com/tonyprimerano/profile.html
I need to work on the module edit mode so users can select the fortune type. And I also need to look into a way to have different fortunes display on the same page. Just in case 1 fortune isn't enough. :-)