/Main_Page

::You must have ninja focus to complete your mission::NinjaFocus::

PHP Spell Check

Views:


This is an php spell checker which uses the pspell binary (rather than a php extension which had it's limitations in 2006). It doesn't require javascript and is fairly accessible with it's inline form.


Contents


spellcheck.php

A generic spell checking class

<?php
/*  spellchecker.php -- *nix pspell binary based spellchecker 
    Copyright 2006 Kieran Whitbread
    
    aspell call and results text parsing based on work by Chris 
    Snyder (csnyder@chxo.com)
        
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  
    02111-1307, USA. */
    
class spellchecker
/*  instanstiate with: 
    $sc = new spellchecker($someTextToCheck);
    
    Optionally specify a custom dictionary either as a simple array
    of words or as a file-path (string) pointing to a correctly 
    formatted pspell personal dictionary file. Use either: 
    $sc = new spellchecker($someTextToCheck);
    or
    $sc = new spellchecker($someTextToCheck, $dictionary);
    $sc->customDictionary($dictionary);
    Note: use only letters in the personal dictionary!
    
    Change text with:
    $sc->setText($someTextToCheck);
    
    Set the pspell suggestion mode to one of bad-spellers, normal, fast (default), ultra:
    $sc->setSuggestionMode($mode);
    
    Check spelling with:
    $sc->getSpellingMistakes();
    
    Iterate mistakes/sugesstions with:
    $myArray = $sc->nextSpellingMistake();
    Returns an array containing: id, word, line, character index, array of sugesstions
    
    Correct spelling with:
    $sc->setCorrection($id, $replacementWord);
    
    Pull out the corrected text with:
    $text = $sc->getCorrectedText();
    
    In PHP4 delete temp files etc when the object is finished with:
    $sc->destroy();
    
    Can safely be stored in a session or serialised and used across sessions with serilazise/unserialize() 
    
    */
{
    protected $customDict = false;
    protected $files = array();
    protected $form = array('docType' => array(
                                'qualifiedName' => 'html',
                                'publicId' => '-//W3C//DTD XHTML 1.0 Transitional//EN',
                                'systemId' => 'http://localhost/xhtml1-transitional.dtd',
                               )
                            );
    protected $id = NULL;
    protected $spellingMistakes = array();
    protected $suggestionMode = 'fast';
    protected $results = array();
    protected $tempFiles = array();
    protected $text = NULL;
    
    private $pspellCmd = 'cat %s | /usr/bin/aspell -a -H --lang=en --sug-mode=%s';
    private $pspellPersonalDictArg = ' --personal=%s';

    public $textIsHTML = false;
    
    public function __construct($text, $customDict=NULL)
    {
        if ($text)
        {
            $this->setText($text);
        }
        if ($customDict)
        {
            $this->customDictionary($customDict);
        }
    }
    public function __destruct()
    // Close all files and delete temporary files
    {
        if ($this->tempFiles)
        {
            reset($this->tempFiles);
            foreach ($this->tempFiles as &$tempFile)
            {
                if ($tempFile)
                {
                    if ($tempFile['handle'] && gettype($tempFile['handle']) == 'resource')
                    {
                        fclose($tempFile['handle']);
                    }
                    if (isset($tempFile['file']) && is_file($tempFile['file']))
                    {
                        unlink($tempFile['file']);
                    }
                }
                unset($tempFile);
            }
        }
        if ($this->files)
        {
            reset($this->files);
            while (list($key) = each($this->files))
            // in PHP5 this could be: foreach ($this->files as &$file)
            // PHP 4 doesn't support references in a foreach loop
            {
                $file = $this->files[$key];
                if ($file)
                {
                    if ($file['handle'])
                    {
                        fclose($file['handle']);
                    }
                }
                unset($file);
            }
        }
    }
    public function __sleep()
    // close files on serialize()
    {
        $this->__destruct();
        return array_keys(get_object_vars(&$this));
    }
    public function __wakeup()
    {
        $this->setText($this->text);
        if ($this->customDict)
        {
            $this->customDictionary($this->customDict);
        }
    }
    protected function appendElement($element, $newElement, $contents='', $attrs=array())
    {
        if (is_object($element) && $newElement)
        {
            if (!is_object($newElement) && is_string($newElement))
            {
                $newElement = $this->form['doc']->createElement($newElement);
            }
            elseif (!is_object($newElement))
            {
                return false;
            }
            if ($attrs && is_array($attrs))
            {
                foreach ($attrs as $name => $value)
                {
                    $newElement->setAttribute($name, $value);
                }
            }
            if ($contents)
            {
                if (is_string($contents) || is_numeric($contents))
                {
                    $contents = $this->form['doc']->createTextNode($contents);
                }
                if (is_object($contents))
                {
                    $newElement->appendChild($contents);
                }
            }
            return $element->appendChild($newElement);
        }
        return false;
    }
/* Old php4 version
    protected function appendElement($element, $newElement, $contents='', $attrs=array())
    {
        if (is_object($element) && $newElement)
        {
            if (!is_object($newElement) && is_string($newElement))
            {
                $newElement = $this->form['doc']->create_element($newElement);
            }
            elseif (!is_object($newElement))
            {
                return false;
            }
            if ($attrs && is_array($attrs))
            {
                foreach ($attrs as $name => $value)
                {
                    $newElement->set_attribute($name, $value);
                }
            }
            if ($contents)
            {
                if (is_string($contents))
                {
                    $contents = $this->form['doc']->create_text_node($contents);
                }
                if (is_object($contents))
                {
                    $newElement->append_child($contents);
                }
            }
            return $element->append_child($newElement);
        }
        return false;
    } */
    protected function correctText()
    {
        $currentLine = 0;
        $offset = 0;
        $text = NULL;
        reset($this->spellingMistakes);
        foreach ($this->spellingMistakes as $mistake)
        {
            if (isset($mistake['choice']) && (strlen(trim($mistake['choice'])) > 0))
            {
                $choice = $mistake['choice'];
                $choiceLength = strlen($mistake['choice']);
                $word = $mistake['word'];
                $wordLength = strlen($mistake['word']);
                $line = $mistake['line'];
                $character = $mistake['character'];
                if ($currentLine != $line)
                {
                    $offset = 0;
                    $currentLine = $line;
                }
                unset($text);
                $text = &$this->text[$line];
                $anteText = substr($text, 0, ($character + $offset));
                $postText = substr($text, ($character + $wordLength + $offset));
                $offset = $offset + ($choiceLength - $wordLength);
                $text = $anteText.$choice.$postText;
            }
        }
    }
    private function createDocumentObject()
    {
        $docType = DOMImplementation::createDocumentType($this->form['docType']['qualifiedName'], $this->form['docType']['publicId'], $this->form['docType']['systemId']);
        $this->form['doc'] = DOMImplementation::createDocument(null, $this->form['docType']['qualifiedName'], $docType);
        $this->form['doc']->encoding = 'UTF-8';
        $this->form['doc']->validateOnParse = true;
        $this->form['doc']->formatOutput = true;
    }
    public function customDictionary($customDict)
    // Generate a custom/personal dictionary to provide pspell with a list of correctly spelt,
    // unusual words. Can pass an array of words or the path to a valid pspell dictionary file
    {
        if (is_array($customDict))
        {
            $this->tempFile('customDict');
            $customEntryCount = count($customDict);
            fputs ($this->tempFiles['customDict']['handle'], "personal_ws-1.1 en $customEntryCount\n");
            foreach ($customDict as $entry)
            {
                // pspell can only handle aplha characters and ' (apostrophies)
                if (preg_match("/^[a-zA-Z|']+$/", $entry)) fputs($this->tempFiles['customDict']['handle'], "$entry\n");
            }
            fflush($this->tempFiles['customDict']['handle']);
        }
        elseif (!is_array($customDict) && is_file($customDict))
        {
            $this->files['customDict']['file'] = $customDict;
        }
        else
        {
            return false;
        }
        $this->customDict = $customDict;
        return true;
    }
    public function getCorrectedText()
    {
        $this->correctText();
        if ($this->text)
        {
            $text = implode("\n", $this->text);
        }
        else
        {
            $text = '';
        }
        return $text;
    }
    public function getForm($method='post', $action='')
    {
        if (!$action)
        {
            $action = $_SERVER['PHP_SELF'];
        }
        
        // create the basic form layout
        $this->createDocumentObject();
        $html = $this->form['doc']->getElementsByTagName('html')->item(0);
        $head = $this->appendElement($html, 'head');
        $this->appendElement($head, 'title', 'Form');
        $this->appendElement($head, 'meta', null, array('http-equiv'=>'Content-Type', 'content'=>'text/html; charset=UTF-8'));
        $body = $this->appendElement($html, 'body');
        $this->form['root'] = $this->appendElement($body, 'form');
        $this->setMethod($method);
        $this->setAction($action);
        $this->form['fieldset'] = $this->appendElement($this->form['root'], 'fieldset');
        if ($this->textIsHTML)
        {
            $this->form['contents'] =& $this->form['fieldset'];
        }
        else
        {
            $this->form['contents'] = $this->appendElement($this->form['fieldset'], 'p');
        }
        
        // parse spelling mistakes and build the contents of the form;
        $text = NULL;
        $index = 0;
        reset($this->spellingMistakes);
        while ($index < count($this->text))
        {
            $mistakes = array();
            $offset = 0;
            foreach ($this->spellingMistakes as $mistake)
            {
                if ($mistake['line'] == $index)
                {
                    $mistakes[] = $mistake;
                }
            }
            if ($mistakes)
            {
                foreach ($mistakes as $mistake)
                {
                    // Get plain vars out of the array
                    $word = $mistake['word'];
                    $wordLength = strlen($mistake['word']);
                    $line = $mistake['line'];
                    $character = $mistake['character'];
                    $suggestions = $mistake['suggestions'];
                    $id = $mistake['id'];
                    
                    // Get text between the last mistake on this line and the current one
                    $anteText = substr($this->text[$index], $offset, ($character - $offset));
                    if ($anteText)
                    {
                        $anteText = htmlentities($anteText);
                        $anteText = $this->form['doc']->createTextNode($anteText."\n");
                        $this->appendElement($this->form['contents'], $anteText);
                    }
                    // Then adjust the offset, ready for next time around this loop.
                    $offset = $character + $wordLength;

                    // Generate a Select box of suggestions, use it to replace the spelling mistake
                    $select = $this->form['doc']->createElement('select');
                    if ($this->id)
                    {
                        $select->setAttribute('name', $this->id.'-mistake'.$id);
                    }
                    else
                    {
                        $select->setAttribute('name', 'mistake'.$id);
                    }
                    $select->setAttribute('title','Spelling mistake: '.$word);
                    $this->appendElement($select, 'option', $word); 
                    foreach ($suggestions as $suggestion)
                    {
                        $this->appendElement($select, 'option', $suggestion, array('value' => $suggestion));
                    }
                    $this->appendElement($this->form['contents'], $select);
                }
                
                // Any text left at the end of the line?
                $postText = substr($this->text[$index], $offset);
                if ($postText)
                {
                    $postText = htmlentities($postText);
                    $postText = $this->form['doc']->createTextNode($postText."\n");
                    $this->appendElement($this->form['contents'], $postText);
                }
            }
            else
            {
                $text = $this->form['doc']->create_text_node($this->text[$index]."\n");
                $this->appendElement($this->form['contents'], $text);
            }
            $index++;
            $this->appendElement($this->form['contents'], 'br');
        }
        $submitAttrs = array(
                            'type' => 'submit',
                            'class' => 'submit',
                            'value' => 'Submit',
                        );
        $this->appendElement($this->form['root'], 'input', '', $submitAttrs);
        $resetAttrs = array(
                            'type' => 'reset',
                            'class' => 'submit',
                            'value' => 'Undo Changes',
                        );
        $this->appendElement($this->form['root'], 'input', '', $resetAttrs);
        $form = $this->form['doc']->saveXML($this->form['root']);
        return $form;
    }
    public function getMistakeCount()
    {
        return count($this->spellingMistakes);
    }
    public function getSpellingMistakes()
    // Check the previously supplied text with pspell and parse the results.
    // Results are saved for later use.
    {
        $this->spellingMistakes = array();
        $mistakes = $this->pspell();
        // DEBUG - remove this next line!
        $this->pspellReturn = $mistakes;
        // $mistakes: & <suspect word> <num suggestions> <position>: <suggest1>, <suggest2>, ...
        //        or: # <unkown word> <position>
        $line = 0;
        $count = 1;
        if ($mistakes)
        {
            $mistakes = explode("\n", $mistakes);
            foreach ($mistakes as $mistake)
            {
                if (substr($mistake, 0, 1) == '&' || substr($mistake, 0, 1) == '#')
                {
                    if (substr($mistake, 0, 1) == '&')
                    {
                        list($details, $suggestions) = explode(': ', $mistake);
                        $suggestions = split(', ', $suggestions);
                        $details = explode(' ', $details);
                        $character = $details[3] - 1;
                    }
                    elseif (substr($mistake, 0, 1) == '#')
                    {
                        $details = explode(' ', $mistake);
                        $suggestions = array();
                        $character = $details[2] - 1;
                    }
                    $word = $details[1];
                    $this->spellingMistakes[] = array(  'id' => $count,
                                                        'word' => $word,
                                                        'line' => $line,
                                                        'character' => $character,
                                                        'suggestions' => $suggestions,
                                                    );
                    $count++;
                }
                elseif (!trim($mistake))
                {
                    $line++;
                }
            }
            reset($this->spellingMistakes);
            return true;
        }
        else
        {
            return false;
        }
    }
    public function nextSpellingMistake()
    {
        if ($this->spellingMistakes)
        {
            $mistake = current($this->spellingMistakes);
            next($this->spellingMistakes);
            return $mistake;
        }
        else
        {
            return false;
        }
    }
    private function pspell()
    // Execute the pspell binary, passing it the text and catching it's output
    {
        if (!$this->text) return null;
        $cmd = $this->pspellCmd;
        if ($this->customDict)
        {
            if ($this->files && $this->files['customDict'] && $this->files['customDict']['file'])
            {
                $customDict = $this->files['customDict']['file'];
            }
            elseif ($this->tempFiles && $this->tempFiles['customDict'] && $this->tempFiles['customDict']['file'])
            {
                $customDict = $this->tempFiles['customDict']['file'];
            }
            if ($customDict)
            {
                $cmd = $cmd.sprintf($this->pspellPersonalDictArg, $customDict);
            }
        }
        $cmd = sprintf($cmd, $this->tempFiles['text']['file'], $this->suggestionMode);
        return shell_exec($cmd);
    }
    public function setAction($action = NULL)
    {
        if (!$action)
        {
            $action = $_SERVER['PHP_SELF'];
        }
        if(is_string($action))
        {
            $this->form['root']->setAttribute('action', $action);
        }
    }
    public function setCorrection($id, $choice)
    {
        if (is_numeric($id) && is_string($choice))
        {
            $mistake = &$this->spellingMistakes[($id - 1)];
            if ($mistake['id'] == $id)
            {
                if ($choice != $mistake['word'])
                {
                    $mistake['choice'] = $choice;
                }
                return true;
            }
            else
            {
                return false;
            }
        }
        else
        {
            return false;
        }
    }
    public function setId($id)
    {
        $this->id = $id;
    }
    public function setMethod($method = '')
    {
        switch (strtolower($method))
        {
            case 'get': $method = 'get'; break;
            case 'post': $method = 'post'; break;
            default: $method = 'post';
        }
        $this->form['root']->setAttribute('method', $method);
    }
    public function setSuggestionMode($mode)
    // Adjust the speed/number of suggestions of pspell
    {
        switch ($mode)
        {
            case 'normal':          $this->suggestionMode = 'normal';
                                    return true;
                                    break;
            case 'fast':            $this->suggestionMode = 'fast';
                                    return true;
                                    break;
            case 'ultra':           $this->suggestionMode = 'ultra';
                                    return true;
                                    break;
            case 'bad-spellers':    $this->suggestionMode = 'bad-spellers';
                                    return true;
                                    break;
            default:                return false;
        }
    }
    public function setText($text)
    // Specify the text to be spell-checked
    {
        if ($text && (is_string($text) || (is_array($text) && is_string($text[0]))))
        {
            if (!$this->tempFiles || !$this->tempFiles['text'] || !$this->tempFiles['text']['handle'])
            {
                $this->tempFile('text');
            }
            if (is_string($text))
            {
                $text = explode("\n",$text);
            }
            $this->text = $text;
            fwrite($this->tempFiles['text']['handle'], "!\n");
            foreach($text as $value) 
            {
                // adding the carat to each line prevents the use of pspell commands within the text
                fwrite($this->tempFiles['text']['handle'], "^$value\n");
            }
            fflush($this->tempFiles['text']['handle']);
            return true;
        }
        else
        {
            return false;
        }
    }
    protected function tempFile($name)
    // Create's a unique temporary file
    {
        $fileName = tempnam('/tmp', 'spellchecker');
        $fileHandle = fopen($fileName, 'w') or die('Cannot create temporary file');
        $this->tempFiles[$name]['file'] = $fileName;
        $this->tempFiles[$name]['handle'] = $fileHandle;
    }
}
?>

customdictionary.php

A class that represents a users custom dictionary, which is stored in a mysql database.

<?php /*    customdictionary.php -- simple class to implement a dictionary 
    Copyright 2007 Kieran Whitbread
        
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  
    02111-1307, USA. */

class customdictionary
{
    var $dbConnection = NULL;
    var $id = NULL;
    var $name = NULL;
    
    function __construct($name)
    {
        $this->name = mysql_real_escape_string($name);
        $this->dbConnection = mysql_connect('localhost', 'username', 'password') or die('Could not connect to mysql database');
        mysql_select_db('db_name', $this->dbConnection) or die('Could not use mysql STS database');
        if ($id = mysql_fetch_assoc(mysql_query("SELECT id FROM dictionaries WHERE name = '{$this->name}'")))
        {
            $this->id = $id['id'];
        }
        else
        {
            mysql_query("INSERT INTO dictionaries SET name = '{$this->name}'");
            $this->id = mysql_insert_id();
        }
    }
    function __destruct()
    {
        mysql_close($this->dbConnection);
    }
    function __sleep()
    {
        $this->__destruct();
        return array_keys(get_object_vars(&$this));
    }
    function __wakeup()
    {
        $this->__construct($this->name);
    }
    function customdictionary($name)
    {
        $this->__construct($name);
    }
    function add($entry)
    {
        $entry = trim($entry);
        // pspell can only handle aplha characters and ' (apostrophies)
        if (strlen($entry) && preg_match("/^[a-zA-Z|']+$/", $entry))
        {
            $entry = mysql_real_escape_string($entry);
            return mysql_query("INSERT INTO dictionary_entries SET entry = '$entry', dictionary_id = {$this->id}");
        }
        else
        {
            return false;
        }
    }
    function delete($entry)
    {
        $entry = mysql_real_escape_string($entry);
        return mysql_query("DELETE FROM dictionary_entries WHERE dictionary_entries.dictionary_id = {$this->id} AND dictionary_entries.entry = '$entry'");
    }
    function deleteAll()
    {
        return mysql_query("DELETE FROM dictionary_entries WHERE dictionary_id = {$this->id}");
    }
    function get()
    {
        $entries = array();
        $entriesP = mysql_query("SELECT entry FROM dictionary_entries WHERE dictionary_entries.dictionary_id = {$this->id}");
        if ($entriesP)
        {
            while ($entry = mysql_fetch_assoc($entriesP))
            {
                $entries[] = $entry['entry'];
            }
        }
        return $entries;
    }
}
?>

form.php

This is an old version of Form.php. There is a much newer set of classes for doing all sorts of things with xhtml. Anyway, this is version of form.php that I used when I wrote the spellchecker.

Basically it allows you to build a html form using the DOM. You can (re)populate the form with data and have it validate itself to check that all required fields have been filled in.

<?php

/*	form.php -- for rapidly making accessible forms. 
	Copyright 2006 Kieran Whitbread
		
	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.
	
	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.
	
	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  
	02111-1307, USA. */
	
class form
{
	protected $doc = NULL;
    protected $docType = array(
                            'qualifiedName' => 'html',
                            'publicId' => '-//W3C//DTD XHTML 1.0 Transitional//EN',
                            'systemId' => 'http://localhost/xhtml1-transitional.dtd',
                        );
	protected $required = array();
    protected $root = NULL;
	protected $sections = array();
    protected $xpath = NULL;    
                            
	public function __construct()
	// Initialise the object
	{
        $this->createDocumentObject();
        $html = $this->doc->getElementsByTagName('html')->item(0);
        $head = $this->appendElement($html, 'head');
        $this->appendElement($head, 'title', 'Form');
        $this->appendElement($head, 'meta', null, array('http-equiv'=>'Content-Type', 'content'=>'text/html; charset=UTF-8'));
        $body = $this->appendElement($html, 'body');
        $this->root = $this->appendElement($body, 'form');
		$this->setMethod();
		$this->setAction();
	}
	public function __destruct()
	{
		//
	}
    public function __dump()
    {
        print '<pre>';
        print htmlentities($this->doc->saveXML());
        print '</pre>';
    }
	public function __sleep()
	{
		$this->sections = NULL;
		$this->root = NULL;
		$this->xml = $this->doc->saveXML();
		$this->required = serialize($this->required);
		return array_keys(get_object_vars($this));
	}
	public function __wakeup()
	{
		$this->createDocumentObject();
        $this->doc->loadXML($this->xml);
		$forms = $this->doc->getElementsByTagName('form');
        $this->root = $forms->item(0);
		$fieldsets = $this->doc->getElementsByTagName('fieldset');
		if ($fieldsets)
		{
			$this->sections = array();
			for ($i=0; $i < $fieldsets->length; $i++)
			{
                $fieldset = $fieldsets->item($i);
				$ols = $fieldset->getElementsByTagName('ol');
				if ($ols)
				{
					$this->sections[] = $ols->item(0);
				}
				else
				{
					$this->sections[] = $fieldset;
				}
			}
		}
		$this->required = unserialize($this->required);
	}
	public function addButtons($submit='Submit', $reset='Reset Form', $caption=NULL)
	{
		$this->newSection($legendText=NULL, $caption);
		$section = $this->sections[count($this->sections) - 1];
		if ($submit || $reset)
		{
			$li = $this->appendElement($section, 'li');		
			if ($submit)
			{
				$submitAttrs = array('type' => 'submit', 'value' => $submit, 'class' => 'button');
				$this->appendElement($li, 'input', NULL, $submitAttrs);
			}
			if ($reset)
			{
				$resetAttrs = array('type' => 'reset', 'value' => $reset, 'class' => 'button');
				$this->appendElement($li, 'input', NULL, $resetAttrs);
			}
		}
	}
	public function addCheck($name, $id, $labelText, $value)
	{
		if (!is_string($name) && !is_string($id))
		{
			return false;
		}
		$section = $this->sections[count($this->sections) - 1];
		$li = $this->appendElement($section, 'li', NULL);
		$label = $this->check($name, $id, $labelText, $value);
		$this->appendElement($li, $label);
	}
	public function addChecks($name, $checks)
	{
		if (is_string($name) && $checks && is_array($checks))
		{
			$count = 1;
			foreach($checks as $check)
			{
				$this->addCheck($name.$count, $name.$count, $check['label'], $check['value']);
				$count++;
			}
		}
	}
	public function addFile($labelText, $idName, $required=false, $class=NULL)
	{
		$this->root->setAttribute('enctype', 'multipart/form-data');
		$section = $this->sections[count($this->sections) - 1];
		$li = $this->appendElement($section, 'li');
		if ($required)
		{
			$labelText = $this->requiredText($labelText);
			$this->requiredValue($idName);
		}
		$this->appendElement($li, 'label', $labelText, array('for' => $idName));
		$attrs = array('type' => 'file', 'name' => $idName, 'id' => $idName);
		if($class)
		{
			$attrs['class'] = $class;
		}
		$this->appendElement($li, 'input', NULL, $attrs);
	}
	public function addHidden($name, $value)
	{
		$this->appendElement($this->root, 'input', NULL, array('type'=>'hidden', 'id'=>$name, 'name'=>$name, 'value'=>$value));
	}
	public function addRadio($name, $id, $labelText, $value)
	{
		if (!is_string($name) || !is_string($id))
		{
			return false;
		}
		$section = $this->sections[count($this->sections) - 1];
		$li = $this->appendElement($section, 'li', NULL);
		$label = $this->radio($name, $id, $labelText, $value);
		$this->appendElement($li, $label);
	}
	public function addRadios($name, $radios, $required=false)
	{
		if (is_string($name) && $radios && is_array($radios))
		{
			if ($required)
			{
				$this->requiredValue($name);
			}
			$count = 1;
			foreach($radios as $radio)
			{
				$this->addRadio($name, $name.$count, $radio['label'], $radio['value']);
				$count++;
			}
		}
	}
	public function addSelectBox($labelText, $idName, $options, $required=false)
	{
		if (is_string($idName) && $options && is_array($options))
		{
			$section = $this->sections[count($this->sections) - 1];
			$li = $this->appendElement($section, 'li');
			if($required)
			{
				$labelText = $this->requiredText($labelText);
				$this->requiredValue($idName);
			}
			$this->appendElement($li, 'label', $labelText, array('for'=>$idName));
			$attrs = array(
							'name' => $idName,
							'id' => $idName,
						);
			$select = $this->appendElement($li, 'select', NULL, $attrs);
			$this->appendElement($select, 'option');
			foreach($options as $option)
			{
				$this->appendElement($select, 'option', $option['contents'], array('value'=>$option['value']));
			}
		}
	}
	public function addSmallRadios($name, $radios, $legendText, $required=false)
	{
		if (is_string($name) && $radios && is_array($radios))
		{
			$count = 1;
			$section = $this->sections[count($this->sections) - 1];
			$li = $this->appendElement($section, 'li', NULL, array('class' => 'widelist'));
			$fieldset = $this->appendElement($li, 'fieldset');
			if($required)
			{
				$legendText = $this->requiredText($legendText);
				$this->requiredValue($name);
			}
			$this->appendElement($fieldset, 'legend', $legendText);
			foreach($radios as $radio)
			{
				$radio = $this->radio($name, $name.$count, $radio['label'], $radio['value']);
				$this->appendElement($fieldset, $radio);
				$count++;
			}
		}
	}
	public function addTable($fields, $rows=2, $legendText=NULL, $captionText=NULL, $required=false)
	{
		if (is_array($fields))
		{
			$fieldset = $this->fieldset($legendText, $captionText, $required);
			$table = $this->appendElement($fieldset, 'table');
			$thead = $this->appendElement($table, 'thead');
			$headerRow = $this->appendElement($thead, 'tr');
			foreach ($fields as $field)
			{
				if (isset($field['label']))
				{
					$this->appendElement($headerRow, 'th', $field['label']);
				}
			}
			$tbody = $this->appendElement($table, 'tbody');
			$count = 1;
			while ($count <= $rows)
			{
				$bodyRow = $this->appendElement($tbody, 'tr');
				reset($fields);
				foreach ($fields as $field)
				{
					if (isset($field['name']) && is_string($field['name']) && !is_numeric($field['name']{1}))
					{
						if ($required)
						{
							$this->requiredValue($field['name'].$count);
						}
						$attrs = array('type' => 'text', 'name' => $field['name'].$count, 'id' => $field['name'].$count);
						if (isset($field['length']) && is_numeric($field['length']))
						{
							$attrs['size'] = $field['length'];
						}
						$tableData = $this->appendElement($bodyRow, 'td');
						$this->appendElement($tableData, 'input', NULL, $attrs);
					}
				}
				$count++;
			}
		}
	}
	public function addTextArea($labelText, $idName, $required=false, $rows=5, $cols=60, $value=NULL, $class=NULL)
	{
		if (!is_string($idName) || !is_numeric($rows) || !is_numeric($cols))
		{
			return false;
		}
		if (!$value)
		{
			$value = ' ';
			}
		$section = $this->sections[count($this->sections) - 1];
		$li = $this->appendElement($section, 'li');
		$label = 'label';
		if($required && is_string($labelText))
		{
			$labelText = $this->requiredText($labelText);
			$this->requiredValue($idName);
		}
		elseif (is_object($labelText))
		{
			$label = $labelText;
			$labelText = NULL;
		}
		$this->appendElement($li, $label, $labelText, array('for' => $idName));
		$attrs = array('name' => $idName, 'id' => $idName, 'rows' => $rows, 'cols' => $cols);
		if ($class)
		{
			$attrs['class'] = $class;
		}
		$this->appendElement($li, 'textarea', $value, $attrs);
	}
	public function addTextBox($labelText, $idName, $required=false, $length=NULL, $value=NULL, $class=NULL)
	{
		$section = $this->sections[count($this->sections) - 1];
		$li = $this->appendElement($section, 'li');
		if($required)
		{
			$labelText = $this->requiredText($labelText);
			$this->requiredValue($idName);
		}
		$this->appendElement($li, 'label', $labelText, array('for' => $idName));
		$attrs = array('type' => 'text', 'name' => $idName, 'id' => $idName);
		if($length)
		{
			$attrs['size'] = $length;
		}
		if($value)
		{
			$attrs['value'] = $value;
		}
		if($class)
		{
			$attrs['class'] = $class;
		}
		$this->appendElement($li, 'input', NULL, $attrs);
	}
	protected function appendElement($element, $newElement, $contents='', $attrs=array())
	{
		if (is_object($element) && $newElement)
		{
			if (!is_object($newElement) && is_string($newElement))
			{
				$newElement = $this->doc->createElement($newElement);
			}
			elseif (!is_object($newElement))
			{
				return false;
			}
			if ($attrs && is_array($attrs))
			{
				foreach ($attrs as $name => $value)
				{
					$newElement->setAttribute($name, $value);
				}
			}
			if ($contents)
			{
				if (is_string($contents) || is_numeric($contents))
				{
					$contents = $this->doc->createTextNode($contents);
				}
				if (is_object($contents))
				{
					$newElement->appendChild($contents);
				}
			}
			return $element->appendChild($newElement);
		}
		return false;
	}
	protected function check($name, $id, $labelText, $value)
	{
		$label = $this->doc->createElement('label');
		$label->setAttribute('for', $id);
		$attrs = array('type' => 'checkbox', 'name' => $name, 'id' => $id, 'value' => $value);
		$this->appendElement($label, 'input', NULL, $attrs);
		$labelText = $this->doc->createTextNode($labelText);
		$label->appendChild($labelText);
		return $label;
	}
    private function createDocumentObject()
    {
        $docType = DOMImplementation::createDocumentType($this->docType['qualifiedName'], $this->docType['publicId'], $this->docType['systemId']);
        $this->doc = DOMImplementation::createDocument(null, $this->docType['qualifiedName'], $docType);
        $this->doc->encoding = 'UTF-8';
        $this->doc->validateOnParse = true;
        $this->doc->formatOutput = true;
    }
	protected function fieldset($legendText=NULL, $captionText=NULL, $required=false)
	{
		$fieldset = $this->appendElement($this->root, 'fieldset');
		$legend = 'legend';
		$caption = 'p';
		if ($legendText && is_object($legendText))
		{
			$label = $labelText;
			$labelText = NULL;
		}
		if ($legendText)
		{
			$legend = $this->appendElement($fieldset, $legend, $legendText);
		}
		if ($required && !is_object($captionText))
		{
			$captionText = $this->requiredText($captionText);
		}
		elseif (is_object($captionText))
		{
			$caption = $captionText;
			$captionText = NULL;
		}
		if (is_object($caption) || $captionText)
		{
			$this->appendElement($fieldset, $caption, $captionText);
		}
		return $fieldset;
	}
	protected function getElementsByNameAttr($name)
	{
        if (!$this->xpath) $this->xpath = new DOMXPath($this->doc);
        return $this->xpath->evaluate('//descendant::*[@name="'.$name.'"]', $this->root);
	}
	public function getForm()
	{
        $form = $this->doc->saveXML($this->root);
		return $form;
	}
	public function getSubmissionVars()
	{
		$method = strtolower($this->root->getAttribute('method'));
		if ($method == 'get')
		{
			$vars = $_GET;
		}
		elseif ($method == 'post')
		{
			$vars = $_POST;
		}
		if (isset($vars))
		{
			if ($this->setVars($vars))
			{
				return $vars;
			}
		}
		else
		{
			return false;
		}
	}
	public function newSection($legendText='', $captionText='', $required=false, $class=NULL)
	{
		$fieldset = $this->fieldset($legendText, $captionText, $required);
		if ($class)
		{
			$attrs = array('class' => 'widelist');
		}
		else
		{
			$attrs = NULL;
		}
		$this->sections[] = $this->appendElement($fieldset, 'ol', NULL, $attrs);
	}
	protected function radio($name, $id, $labelText, $value)
	{
		$label = $this->doc->createElement('label');
		$label->setAttribute('for', $id);
		$attrs = array('type' => 'radio', 'name' => $name, 'id' => $id, 'value' => $value);
		$this->appendElement($label, 'input', NULL, $attrs);
		$labelText = $this->doc->createTextTode($labelText);
		$label->appendChild($labelText);
		return $label;
	}
	protected function requiredText($labelText)
	{
		$strong = $this->doc->createElement('strong');
		if(strlen($labelText) == 0)
		{
			$labelText = 'Required';
		}
        $labelText = $this->doc->createTextNode($labelText.' *');
		$strong->appendChild($labelText);
		return $strong;
	}
	public function requiredValue($name, $alternatives=array())
	{
		if ($alternatives)
		{
			$this->required[$name]['alternatives'] = $alternatives;
		}
		else
		{
			$this->required[$name] = true;
		}
	}
	public function setAction($action = NULL)
	{
		if (!$action)
		{
			$action = $_SERVER['PHP_SELF'];
		}
		if(is_string($action))
		{
			$this->root->setAttribute('action', $action);
		}
	}
	public function setMethod($method = '')
	{
		switch (strtolower($method))
		{
			case 'get': $method = 'get'; break;
			case 'post': $method = 'post'; break;
			default: $method = 'post';
		}
		$this->root->setAttribute('method', $method);
	}
	public function setVars($vars)
	{
        $this->doc->validate();
		$return = false;
		if (is_array($vars))
		{
			foreach($vars as $name => $value)
			{
				$element = NULL;
				$elements = NULL;
				$element = $this->doc->getElementById($name);
				if ($element)
				{
					$return = true;
					switch ($element->tagName)
					{
						case 'input':		switch ($element->getAttribute('type'))
											{
                                                
												case 'checkbox':	$element->setAttribute('checked', 'checked');
																	break;
												case 'text':		
												case 'hidden':		$element->setAttribute('value', $value);
																	break;
											};
											break;
						case 'textarea':	$textNode = $element->firstChild;
                                            $newTextNode = $this->doc->createTextNode($value);
											if ($textNode)
											{
                                                $element->replaceChild($newTextNode, $textNode);
											}
											else
											{
												$this->appendElement($element, $newTextNode);
											}
											break;
						case 'select':		$options = $element->childNodes;
											for ($i = 0; $i < $options->length; $i++)
											{
                                                $option = $options->item($i);
												if ((get_class($option) == 'DOMElement') && ($option->getAttribute('value') == $value))
												{
													$option->setAttribute('selected', 'selected');
												}
											}
											break;
					}
				}
				else // radio buttons?
				{
					$elements = $this->getElementsByNameAttr($name);
					if ($elements)
					{
						$return = true;
						for ($i = 0; $i < $elements->length; $i++)
						{
                            $element = $elements->item($i);
							if ($element->getAttribute('value') == $value)
							{
								$element->setAttribute('checked', 'checked');
							}
						}
					}
				}
			}
		}
		return $return;
	}
	public function validateForm()
	{
		$result = false;
		$vars = $this->getSubmissionVars();
		if($vars)
		{
			$result = true;
			foreach ($this->required as $requirement => $alternatives)
			{
				if (!isset($vars[$requirement]) || (strlen(trim($vars[$requirement])) == 0))
				{
					$result = false;
				}
			}
		}
		return $result;
	}
}
?>

Main Menu

Personal tools

Toolbox