1. '; $usePersonalDict = true; //set to false if you don't want to use a personal dictionary. //if pspell doesn't exist, then include the pspell wrapper for aspell if (!function_exists('pspell_suggest')) { define('ASPELL_BIN', '/path/to/aspell'); //set path to aspell if you need to and uncomment this line require_once("pspell_comp.php"); } //these four lines create and configure a link to the pspell module $path_to_personal_dictionary = $_SERVER["DOCUMENT_ROOT"] . "/spell_checker/personal_dictionary/personal_dictionary.txt"; // custom dictionary file $pspell_config = pspell_config_create("en"); pspell_config_mode($pspell_config, PSPELL_FAST); if ($usePersonalDict) { pspell_config_personal($pspell_config, $path_to_personal_dictionary); // allows the use of a custom dictionary (Thanks to Dylan Thurston for this addition). } $pspell_link = pspell_new_config($pspell_config); require_once("cpaint2.inc.php"); //AJAX library file $cp = new cpaint(); $cp->register('showSuggestions'); $cp->register('spellCheck'); $cp->register('switchText'); $cp->register('addWord'); $cp->start(); $cp->return_data(); /************************************************************* * showSuggestions($word, $id) * * The showSuggestions function creates the list of up to 10 * suggestions to return for the given misspelled word. * * $word - The misspelled word that was clicked on * $id - The id of the span containing the misspelled word. * *************************************************************/ function showSuggestions($word, $id) { global $usePersonalDict; //bool to set usage of personal dictionary global $pspell_link; //the global link to the pspell module global $cp; //the CPAINT object $retVal = ""; $suggestions = pspell_suggest($pspell_link, $word); //an array of all the suggestions that psepll returns for $word. $numSuggestions = count($suggestions); $numSuggestionsToReturn = 10; //the maximum number of suggestions to return. //if the number of suggestions returned by pspell is less than the maximum number, just use the number of suggestions returned. if ($numSuggestions < $numSuggestionsToReturn) { $tmpNum = $numSuggestions; } else { //else, just the custom number $tmpNum = $numSuggestionsToReturn; } if ($tmpNum > 0) { //$retVal .= ""; //this creates the table of suggestions. //in the onclick event it has a call to the replaceWord javascript function which does the actual replacing on the page for ($i=0; $i<$tmpNum; $i++) { $retVal .= "
      " . $suggestions[$i] . "
      "; } if ($usePersonalDict) { $retVal .= "
      Add To Dictionary
      "; } } else { $retVal .= "No Suggestions"; } $cp->set_data($retVal); //the return value - a string containing the table of suggestions. } //end showSuggestions function /************************************************************* * spellCheck($string) * * The spellCheck function takes the string of text entered * in the text box and spell checks it. It splits the text * on anything inside of < > in order to prevent html from being * spell checked. Then any text is split on spaces so that only * one word is spell checked at a time. This creates a multidimensional * array. The array is flattened. The array is looped through * ignoring the html lines and spell checking the others. If a word * is misspelled, code is wrapped around it to highlight it and to * make it clickable to show the user the suggestions for that * misspelled word. * * $string - The string of text from the text box that is to be * spell checked. * *************************************************************/ function spellCheck($string, $varName) { global $pspell_link; //the global link to the pspell module global $cp; //the CPAINT object $retVal = ""; $isThereAMisspelling = false; //at first we just assume that the text is all correctly spelled unless we find differently. $string = stripslashes_custom($string); //we only need to strip slashes if magic quotes are on $string = remove_word_junk($string); //make all the returns in the text look the same $string = preg_replace("/\r?\n/", "\n", $string); //splits the string on any html tags, preserving the tags and putting them in the $words array $words = preg_split("/(<[^<>]*>)/", $string, -1, PREG_SPLIT_DELIM_CAPTURE); $numResults = count($words); //the number of elements in the array. //this loop looks through the words array and splits any lines of text that aren't html tags on space, preserving the spaces. for ($x=0; $x<$numResults; $x++) { if (!preg_match("/<[^>]*>/", $words[$x])) { //if the line is not an html tag $words[$x] = preg_split("/(\s+)/", $words[$x], -1, PREG_SPLIT_DELIM_CAPTURE); //then split it on the spaces } else { //otherwise, we wrap all the html tags in comments to make them not displayed $words[$x] = preg_replace("//", ">-->", $words[$x]); } } $words = flattenArray($words); //flatten the array to be one dimensional. $numResults = count($words); //the number of elements in the array after it's been flattened. //goes through the words array again and spell checks the words as long as it's not an html and it's matches /[A-Z']{1,16}/i for ($i=0; $i<$numResults; $i++) { if (!preg_match("/<[^>]*>/", $words[$i])) { //ignore any html tags preg_match("/[A-Z']{1,16}/i", $words[$i], $tmp); //get the word that is in the array slot $i $tmpWord = $tmp[0]; //should only have one element in the array anyway, so it's just assign it to $tmpWord //if it's misspelled then we set isAllCorrect to false because we found a misspelling. //And we replace the word in the array with the span that highlights it and gives it an onClick parameter to show the suggestions. if (!pspell_check($pspell_link, $tmpWord)) { $isThereAMisspelling = true; $onClick = "onclick=\"setCurrentObject(" . $varName . "); showSuggestions('" . addslashes($tmpWord) . "', '" . $varName . "_" . $i . "_" . addslashes($tmpWord) . "');\""; $words[$i] = str_replace($tmpWord, "" . stripslashes($tmpWord) . "", $words[$i]); } $words[$i] = preg_replace("/\n/", "
      ", $words[$i]); //replace any breaks with
      's, for html display } }//end for $string = ""; //return string //if there were no misspellings, start the string with a 0. if (!$isThereAMisspelling) { $string = "0"; } else { //else, there were misspellings, start the string with a 1. $string = "1"; } for ($i=0; $i<$numResults; $i++) { $string .= $words[$i]; } //remove comments from around all html tags except for because we don't want the links to be clickable //but we want the html to be rendered in the div for preview purposes. $string = preg_replace("//i", "
      ", $string); $string = preg_replace("//i", "

      ", $string); $string = preg_replace("//i", "

      ", $string); $string = preg_replace("//i", "", $string); $string = preg_replace("//i", "", $string); $string = preg_replace("//i", "", $string); $string = preg_replace("//i", "", $string); $string = preg_replace("//i", "", $string); $string = preg_replace("//i", "", $string); $string = preg_replace("//i", "", $string); $string = preg_replace("//i", "", $string); $string = preg_replace("//i", "
        ", $string); $string = preg_replace("//i", "
      ", $string); $string = preg_replace("//i", "
    2. ", $string); $string = preg_replace("//i", "
    3. ", $string); $string = preg_replace("//i", "", $string); $cp->set_data($string); //return value - string containing all the markup for the misspelled words. } //end spellCheck function /************************************************************* * addWord($str) * * This function adds a word to the custom dictionary * * @param $str The word to be added *************************************************************/ function addWord($str) { global $pspell_link; //the global link to the pspell module global $cp; //the CPAINT object $retVal = ""; pspell_add_to_personal($pspell_link, $str); if (pspell_save_wordlist($pspell_link)) { $retVal = "Save successful!"; } else { $retVal = "Save Failed!"; } $cp->set_data($retVal); } //end addWord function /************************************************************* * flattenArray($array) * * The flattenArray function is a recursive function that takes a * multidimensional array and flattens it to be a one-dimensional * array. The one-dimensional flattened array is returned. * * $array - The array to be flattened. * *************************************************************/ function flattenArray($array) { $flatArray = array(); foreach ($array as $subElement) { if (is_array($subElement)) { $flatArray = array_merge($flatArray, flattenArray($subElement)); } else { $flatArray[] = $subElement; } } return $flatArray; } //end flattenArray function /************************************************************* * stripslashes_custom($string) * * This is a custom stripslashes function that only strips * the slashes if magic quotes are on. This is written for * compatibility with other servers in the event someone doesn't * have magic quotes on. * * $string - The string that might need the slashes stripped. * *************************************************************/ function stripslashes_custom($string) { if (get_magic_quotes_gpc()) { return stripslashes($string); } else { return $string; } } /************************************************************* * addslashes_custom($string) * * This is a custom addslashes function that only adds * the slashes if magic quotes are off. This is written for * compatibility with other servers in the event someone doesn't * have magic quotes on. * * $string - The string that might need the slashes added. * *************************************************************/ function addslashes_custom($string) { if (!get_magic_quotes_gpc()) { return addslashes($string); } else { return $string; } } /************************************************************* * remove_word_junk($t) * * This function strips out all the crap that Word tries to * add to it's text in the even someone pastes in code from * Word. * * $t - The text to be cleaned * *************************************************************/ function remove_word_junk($t) { $a=array( "\xe2\x80\x9c"=>'"', "\xe2\x80\x9d"=>'"', "\xe2\x80\x99"=>"'", "\xe2\x80\xa6"=>"...", "\xe2\x80\x98"=>"'", "\xe2\x80\x94"=>"---", "\xe2\x80\x93"=>"--", "\x85"=>"...", "\221"=>"'", "\222"=>"'", "\223"=>'"', "\224"=>'"', "\x97"=>"---", "\x96"=>"--" ); foreach ($a as $k=>$v) { $oa[]=$k; $ra[]=$v; } //debug_log(implode(",",$oa)); $t=trim(str_replace($oa, $ra, $t)); return $t; }//end remove_word_junk function /************************************************************* * switchText($string) * * This function prepares the text to be sent back to the text * box from the div. The comments are removed and breaks are * converted back into \n's. All the html tags that the user * might have entered that aren't on the approved list: *


      • are stripped out. * The user-entered returns have already been replaced with * $u2026 so that they can be preserved. I replace all the * \n's that might have been added by the browser (Firefox does * this in trying to pretty up the HTML) with " " so that * everything will look the way it did when the user typed it * in the box the first time. * * $string - The string of html from the div that will be sent * back to the text box. * *************************************************************/ function switchText($string) { global $allowed_html; global $cp; //the CPAINT object $string = remove_word_junk($string); $string = preg_replace("//", "", $string); $string = preg_replace("/\r?\n/", " ", $string); $string = stripslashes_custom($string); //we only need to strip slashes if magic quotes are on $string = strip_tags_advanced($string, $allowed_html); $string = preg_replace('{</?span.*?>}i', '', $string); $string = html_entity_decode($string); $cp->set_data($string); //the return value } //end switchText function //============================ // strip_tags_advanced //============================ // // Works like strip_tags, but disallowed tags are converted // to escaped html, rather than being removed. This function // also escapes tags with unsupported attributes (such as // onmouseover). // // $str: The string to strip tags on. // $valid_tags: A string of valid tags. For attributes valid // on a tag, they should be comma-delimited, without // spaces after the commas. // // Thanks to kip for this function!! //==================================================== function strip_tags_advanced($str, $valid_tags) { //validate input if (0 == preg_match('/^(<\\w+(\\s+(\\w+,)*\\w+)?>)*$/', $valid_tags)) { return ''; } //---------------------------------------------------------- //Convert $valid_tags into a regular expression //For example: // // becomes // (b)|(i)|(u)|(a(\s+((href)(=(["][^"<>]+["]|['][^'<>]+[']))?))*)|(img(\s+((src|alt)(=(["][^"<>]+["]|['][^'<>]+[']))?))*) //---------------------------------------------------------- $valid_tag_exp = $valid_tags; //first covert <>'s to (), with ORs between tags $valid_tag_exp = preg_replace('/>/', ')', $valid_tag_exp); $valid_tag_exp = preg_replace('/' $valid_tag_exp = preg_replace('/\\s+((\\w+,)*\\w+)/', '(\\s+(($1)(=(["][^"<>]+["]|[\'][^\'<>]+[\']))?))*', $valid_tag_exp); $valid_tag_exp = preg_replace('/,/', '|', $valid_tag_exp); //---------------------------------------------------------- // Get the number of parenthesis in the expression. //---------------------------------------------------------- $paren_count = substr_count($valid_tag_exp, '('); //---------------------------------------------------------- // Now format the string //---------------------------------------------------------- $result = $str; //first convert any <'s not followed by a letter or / to < $result = preg_replace('{<([^a-z/])}i', '<$1', $result); //now, convert any <'s or >'s that don't have a partner $result = preg_replace('/<([^<>]*)(?=<)/', '<$1', $result); $result = preg_replace('/(?<=>)([^<>]*)>/', '$1>', $result); //now, convert any leading >'s or trailing <'s, which the previous expressions wouldn't pick up $result = preg_replace('/^([^<>]*)>/', '$1>', $result); $result = preg_replace('/<([^<>]*)$/', '<$1', $result); //finally, convert any tags that do not match $valid_tag_pattern to <$tag> $result = preg_replace('{<(?!/?(' . $valid_tag_exp . ')\\s*/?(?=>))([^>]*)>}i', '<$' . ($paren_count + 2) . '>', $result); return $result; }