The Fortune Service

Dec 20, 2011 Published by Tony Primerano

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

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