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. :-)