< Back to Code Samples
<?php
/*************************************************************
 * MadLibs - AJAX powered Mad libs processor
 *
 *    PURPOSE: To do back-end processing of loading, changing, and switching out words.
 *
 *  USAGE: Just read below. It's kind of a standalone thing.
 *
 *  NOTES: This would probably be better written as a web service, but at the time I wrote 
 *          it, I wasn't as familiar with SOAP/WSDL/XML-RPC.
 * ************************************************************/

//
// Connect to the madlibs database. The instantiation of that class is done ABOVE the
// Document Root so that it's harder for anyone to see it from the outside world.
//
require_once('../../../classes/mldb.php'); // $mldb -- uses the MySQL DBO from above.

//
// Begin: Initialize the parts of speech first. These are pre-defined in a table. They are, if I
// remember correctly, paired with descriptive versions ("Adjective") and codified version ("ADJ").

$posQuery "SELECT * FROM partsofspeech";
$mldb->query($posQuery);

while (
$pos $mldb->fetch_object())
{    
$partsOfSpeech[$pos->pos_ID] = $pos->pos; }

// 
// Some very simplistic mode processing. This first bit prevents URL hacking.
//

$mode = isset($_GET['mode']) ? substr($_GET['mode'],0,1) : 0;

switch(
$mode)
{
    case 
1:  // Load a new madlib
        
$txt getMadLib();  // See below
        
$txt addTags($txt);// See below
        
echo substr($txt,1); // Send back AJAX data
        
break;
        
    case 
2:  // Grab a word
        //
        // This is the fancy faux-serialization processing I did. There's some very modest
        // SQL Injection prevention. This was before I wrote the Safe_Query function. pos_ID
        // is the ordinal value of the word's location.
        // 
        
$pos = (isset($_GET['pos_ID'])) ? mysql_escape_string($_GET['pos_ID']) : "1";
        echo 
getRandomWord($pos); // Send back AJAX data, See below for function definition.
        
break;
        
    case 
3// Grab all words
        // 
        // This is the "go-for-broke-just-fill-out-all-the-words" method. 
        //
        
$output "";
        
//
        // Iterate through key/value pairs. There are possibly some security concerns
        // here that I didn't address. I would probably do this differently now if I re-wrote it.
        //
        
foreach ($_GET as $objID => $posID
        {
            if (
$objID == "mode") continue;
            
$output .= $objID ":" getRandomWord($posID) . ",";
        }
        
$output substr($output,0,-1);  // Strip off the trailing character.
        
echo $output// Send back to AJAX request
        
break;
        
    case 
4// Create new stuff -- Not yet implemented.
        /* $type = (isset($_GET['type']) ? mysql_escape_string($_GET['type']) : "word");
        createNew($type);
        */
        
break;
    case 
5// Handle Queries -- I forget what I wrote this for, but it sounds like a bad idea.
        
break;
    default:
        
// do nothing.
        
break;
}

/** **************************************************
 * createNew() - This function prompts the user for creating a new word / madlib. As
 *                 this feature is not yet implementd, it's kind of irrelevant right now. :)
 * 
 * @param $type  allows for modal choices between creating a new word or a new madlib.
 *               This could probably be done differently.
 * @see          HTML Form tags. 
 * **************************************************/
function createNew ($type)
{
    global 
$mldb;  // hacky. 
    
global $partsOfSpeech;  // ditto. This should be a parameter.
    
    
switch ($type)
    {
        case 
"word":
            echo 
"<fieldset><legend>Word Entry</legend>\r
                <form method=\"post\" action=\"madlibs.php?mode=5&type=word\">\r
                <select name=\"pos\" >\r"
;
            
            foreach (
$partsOfSpeech as $pos_ID => $pos)
            {
                echo 
"<option value=\"$pos_ID\">$pos</option>\r";
            }
            echo 
"</select>\r
                        <label>Enter your word*\r
                        <input type=\"text\" class=\"inputText\" name=\"word\" id=\"wordEntry\" />\r
                    </label>\r
                    <input type=\"submit\" name=\"submit\" />
                </form></fieldset>\r"
;
            break;
        case 
"madlib":
            break;
        default:
            break;
    }
}

/** *************************************************************************
 * getMadLib() - Grab a piping fresh madlib from the database. It's a randomized
 *            SELECT statement. Title is validated.
 * @return   The output result.
 * **************************************************************************/

function getMadLib()
{
    global 
$mldb;  // Very hacky.
    
$mlQuery "SELECT madlib,title FROM madlib ORDER BY RAND() LIMIT 1";
    
$mldb->query($mlQuery);
    
$result $mldb->fetch_object();
    
$title = ($result->title != "") ? $result->title "<em>Untitled</em>";
    
$output "<div id=\"title\">$title</div>";
    
$output .= $result->madlib;
    return 
$output;
}


/** *************************************************************************
 * addTags() - Makes all parts-of-speech linkable. This would be EASILY done with
 *                 a regex, if I was re-doing it now. All parts of speech appear as
 *              bracketed references. So something like [NOUN] or [ADJECTIVE] shoes.
 *
 * @param   $txt    the raw text pulled from the database.
 * @return   The output result.
 * **************************************************************************/

function addTags($txt)
{
    global 
$mldb// *sigh*
    
global $partsOfSpeech;

    
// To prevent problems if there's a word at the start of the text. I forget 
    // why this was an issue. It may not even be necessary.
    
$txt "." $txt
    
    
// Foreach parts of speech : $pos_ID is the "ADJ" version, $pos is the "Adjective" version. 
    // Essentially what this does is iterate through each parts of speech, explode the serialized
    // text, manipulate the components, and then concatenate it back together. It re-explodes it 
    // for each part of speech -- but each time it explodes the text, the text separates into different
    // segments.
    // i.e.:   .[NOUN] was a very [ADJECTIVE] [NOUN]. He [VERB] in a [ADJECTIVE] shoe.
    // For "Noun" this would split into:
    // [0] => .
    // [1] => was a very [ADJECTIVE]
    // [2] => . He [VERB] in a [ADJECTIVE] shoe.
    //
    // But for "Adjective" it would split to:
    // [0] => .[NOUN] was a very
    // [1] => [NOUN]. He [VERB] in a
    // [2] => shoe.
    //
    // Interleaving the correct links with this is very easy when it's broken up like this.
    //
    
foreach ($partsOfSpeech as $pos_ID => $pos)
    {
        
// What we're looking for.
        
$needle "[" $pos "]";
        
$count "0";
        
$output "";

        
// My hacky de-serialization.
        
$parseArray explode($needle$txt);

        foreach (
$parseArray as $index => $segment)
        {
            if (
$count 0)
                {
                    
//
                    // Specifies the ordinal of this part of speech. NOUN_1 or PART_OF_BODY_3
                    //
                    
$thisID str_replace(" ","_",$pos) . "_" $count;

                    
//
                    // This is the actual link structure. It specifies mode 2, sets the Parts of Speech ID of the 
                    // link to the current POS ID, etc.
                    //
                    
$output .= "<a class=\"word\" rel=\"$pos_ID\" id=\"$thisID\" href=\"#nogo\" onclick=\"makerequest('madlibs.php?mode=2&pos_ID=" $pos_ID "','$thisID'); return false;\" title=\"" $pos "\">" strtoupper($pos) . "</a>";
                }
            
$count++;  // Increment the ordinal.
            
$output .= $segment// Concatenate the result so far.
        
}
        
$txt $output// Reset the string.
    
}
    return 
$txt;
}

/** ***************************************************
 * getRandomWord - returns a random word of a particular part of speech.
 * @param $pos_ID - the Part of Speech ID for the word. (i.e. [ADJ])
 * @return The word result.
 * ****************************************************/
function getRandomWord($pos_ID)
{
    global 
$mldb;
    
$wordQuery "SELECT word FROM words WHERE pos_ID='" mysql_real_escape_string($pos_ID) . "' ORDER BY RAND() LIMIT 1";
    
$mldb->query($wordQuery);
    
$word $mldb->fetch_object();
    return 
$word->word;
}
?>