<?php
//
// class.madlibs.php
// version 1.0.0, 3rd September, 2003
//
// Description
//
// This class allows you to easily add a madlibs game to your website.
// You can load the madlib stories in via the file system or a database.
// If using the file system, the stories must contain the title on the
// first line and then story in the rest of the file. If using a database
// then the schema is as follows:
//
// CREATE TABLE madlibs
// (
// id int(11) NOT NULL auto_increment,
// title varchar(255) NOT NULL default '',
// story mediumtext NOT NULL,
// PRIMARY KEY (id)
// )
//
// Stories are requied to have specific tags in them for replacement. The
// format for the tags in the stories as '{TAGNAME}'. See the function
// 'setDefaultTags' for a list of all default tags. The class already comes
// loaded with a vast array of tags, though you can easily add to or remove
// from that list at run time.
//
// Examples of use
//
// Using the file system:
//
// require 'class.madlibs.php';
// $ml = new madlibs();
// $ml->useFS('./stories', '.txt');
// $ml->displayMadlib();
//
// Using the file system:
//
// require 'class.madlibs.php';
// $ml = new madlibs();
// $ml->useDB('username', 'password', 'madlibs', 'mydb', 'localhost');
// $ml->displayMadlib();
//
// Examples of stories
//
// A simple test title
// Yesterday, {OPPOSITESEX} and I went to the beach. We had a really
// {ADJECTIVE} time! We {VERB-ED} with my {NOUN}.
//
// Feedback
//
// There is message board at the following address:
//
// http://php.amnuts.com/forums/index.php
//
// Please use that to post up any comments, questions, bug reports, etc. You
// can also use the board to show off your use of the script.
//
// Support
//
// If you like this script, or any of my others, then please take a moment
// to consider giving a donation. This will encourage me to make updates and
// create new scripts which I would make available to you. If you would like
// to donate anything, then there is a link from my website to PayPal.
//
// Andrew Collington, 2003
// hide@address.com, http://php.amnuts.com/
//
class madlibs
{
var $useType;
var $dbUser;
var $dbPass;
var $dbHost;
var $dbName;
var $dbTbl;
var $dbID;
var $fsPath;
var $fsExt;
var $inText;
var $outText;
var $tags;
var $tagPositions;
//
// the constructor
//
function madlibs()
{
$this->useType = '';
$this->tagPositions = array();
$this->inText = array();
$this->outText = array();
$this->setDefaultTags();
}
//
// set the default replacement tags
//
function setDefaultTags()
{
$this->tags =
array(
'VERB' => 'A verb',
'VERB-ED' => 'A verb ending in \'ed\'',
'VERB-ING' => 'A verb ending in \'ing\'',
'VERB-S' => 'A verb ending in \'s\'',
'NOUN' => 'A noun',
'NOUN-PLURAL' => 'A plural noun',
'ADJECTIVE' => 'An adjective',
'ADVERB' => 'An adverb',
'EMOTION' => 'An emotion',
'NUMBER' => 'A number',
'PLACE' => 'The name of a place',
'ROOM' => 'The name of a room',
'FOOD' => 'The name of some food',
'MALE' => 'A man\'s name',
'FEMALE' => 'A woman\'s name',
'OPPOSITESEX' => 'Name of a member of the opposite sex',
'SAMESEX' => 'Name of a member of the same sex',
'ANIMAL' => 'An animal',
'ANIMAL-PLURAL' => 'An animal (plural)',
'FUNNY' => 'Something funny',
'BODYPART' => 'A body part',
'BODYPART-PLURAL' => 'A body part (plural)',
'CELEBRITY' => 'The name of a celebrity',
'MADEUP' => 'Just make up a word'
);
}
//
// allows you to add new tags to the list on the fly
// $name is the tag name, eg, 'VERB'
// $description is the text displayed to the user, eg, 'A verb'
//
function addTag($name, $description)
{
$this->tags[$name] = $description;
return (array_key_exists($name, $this->tags)) ? TRUE : FALSE;
}
//
// allows you to remove a tag from the tag list on the fly
// $name is the tag name, eg, 'VERB'
//
function deleteTag($name)
{
if (array_key_exists($name, $this->tags))
{
$this->tags[$name] = NULL;
unset($this->tags[$name]);
return TRUE;
}
else
{
return FALSE;
}
}
//
// sets the class to use a MySQL database for the story storage area
// $user is the username used to access to database
// $pass is the password for the user account
// $table is the table name that stores the story information
// $database is the name of the database that contains the $table
// $host is the host address of the database
//
function useDB($user='username', $pass='password', $table='madlibs', $database='demo', $host='localhost')
{
$this->useType = 'db';
$this->dbUser = $user;
$this->dbPass = $pass;
$this->dbHost = $host;
$this->dbName = $database;
$this->dbTbl = $table;
$this->dbID = NULL;
$this->dbID = @mysql_connect($this->dbHost, $this->dbUser, $this->dbPass) or die("Unable to connect to mysql server: {$this->dbHost}");
@mysql_select_db($this->dbName, $this->dbID) or die("Unable to select database: {$this->dbName}");
}
//
// sets the class to use the file system for the story storage area
// $path is the path to the story files
// $extension is the extensions of the story files, including the period if one is used
// the name of the file is arbitrary
//
function useFS($path = 'stories', $extension = '.txt')
{
$this->useType = 'fs';
$this->fsPath = $path;
$this->fsExt = $extension;
}
//
// loads the story information
//
function getStory()
{
if ($this->useType == 'db')
{
$sql = "SELECT * FROM {$this->dbTbl} " .
($_POST['id'] ? "WHERE id = {$_POST['id']}" : "ORDER BY RAND() LIMIT 1");
$result = @mysql_query($sql, $this->dbID);
if (mysql_num_rows($result))
{
$data = @mysql_fetch_object($result);
$this->inText['id'] = $data->id;
$this->inText['title'] = trim(stripslashes($data->title));
$this->inText['story'] = trim(stripslashes($data->story));
}
}
else if ($this->useType == 'fs')
{
if ($_POST['id'])
{
$file = $_POST['id'];
}
else
{
$filelist = array();
if ($dir = @opendir($this->fsPath))
{
while (($file = readdir($dir)) !== FALSE)
{
if ($file == '.' || $file == '..') continue;
if (preg_match("/{$this->fsExt}$/", $file))
{
$filelist[] = $file;
}
}
closedir($dir);
srand((float)microtime() * 10000000);
$file = $filelist[array_rand($filelist)];
}
}
$data = array();
$data = @file($this->fsPath . '/' . $file);
if (!empty($data))
{
$this->inText['id'] = $file;
$this->inText['title'] = trim(@array_shift($data));
$this->inText['story'] = trim(@join('', $data));
}
}
}
//
// displays the madlib
// if the form hasn't been displayed then it will show the form, else it
// will show the story complete with madlib sustitutions
//
function displayMadlib()
{
$this->getStory();
if (!isset($_POST['positions']))
{
if ($this->inText['story'])
{
$this->getTagPositions();
$this->showForm();
}
else
{
echo 'No madlib story has been loaded.';
}
}
else
{
if ($this->inText['story'])
{
$this->decompPositions($_POST['positions']);
$this->replaceTags($_POST['word']);
echo '<div class="madlibTitle">', $this->outText['title'], "</div>\n";
echo '<div class="madlibStory">', nl2br($this->outText['story']), "</div>\n";
}
else
{
echo 'No madlib story has been loaded.';
}
}
}
//
// displays the form the user's words
//
function showForm()
{
echo '<form name="madlibForm" action="', $_SERVER['PHP_SELF'], '" method="post">';
echo '<input type="hidden" name="id" value="', urlencode($this->inText['id']), '">';
echo '<input type="hidden" name="positions" value="', $this->compPositions(), '">';
echo "<p>Please enter the following:</p>\n";
echo '<table border="0" cellpadding="5" cellspacing="0" class="madlibTable">';
foreach ($this->tagPositions as $id => $type)
{
echo '<tr><td>', $this->tags[$type], '</td><td><input type="textbox" name="word[', $id, ']"></td></tr>', "\n";
}
echo '<tr><td colspan="2" align="center"><input type="submit" value="see your madlib"></td></tr>';
echo "\n</table>\n</form>\n";
}
//
// determines where in the tags lie
//
function getTagPositions()
{
foreach ($this->tags as $key => $desc)
{
$positions = array();
$tag = '{' . $key . '}';
$positions = $this->multi_strpos($tag, $this->inText['story']);
if (!empty($positions))
{
foreach ($positions as $place)
{
$this->tagPositions[$place] = $key;
}
}
}
ksort($this->tagPositions);
}
//
// does the tag substitution for the finished story
//
function replaceTags($word_list)
{
$this->outText = $this->inText;
if (!empty($this->tagPositions))
{
$tags = array_reverse($this->tagPositions, TRUE);
foreach ($tags as $position => $type)
{
$tag = '{' . $type . '}';
$this->outText['story'] = substr_replace($this->outText['story'], '<span class="madlibWord">' . $word_list[$position] . '</span>', $position, strlen($tag));
}
}
}
//
// function to determine multiple occurrences of a word in a string
// from a post by arduenn at hotpop dot com on the php.net comments
//
function multi_strpos($pattern, $sequence)
{
$n = -1;
while (ereg($pattern, $sequence))
{
$n++;
$fragment = split($pattern, $sequence);
$trimsize = (strlen($fragment[0]))+1;
$sequence = "*".substr($sequence, $trimsize);
$position[$n] = (strlen($fragment[0]) + $position[($n-1)]);
}
return $position;
}
//
// compresses the tag position array for use in a form
//
function compPositions()
{
return urlencode(base64_encode(serialize($this->tagPositions)));
}
//
// decompresses the tag information array from a string
// $positions is the compressed structure
//
function decompPositions($positions)
{
$this->tagPositions = unserialize(base64_decode(urldecode($positions)));
}
}
?>