* @copyright Copyright © 2006 Sabin Iacob * @version 0.6 * @license http://creativecommons.org/licenses/GPL/2.0/ GNU General Public License */ //{{{ class GenericSpellChecker /** * The generic spell checker class every other spell checker builds upon. * @package AjaxSpellChecker * @subpackage WebService */ class GenericSpellChecker { //{{{ private properties /** * @var string HTML to check for spelling errors * @access private */ var $_html; /** * @var array Plain text → HTML offset translation table * @access private */ var $_offsets; /** * @var array Associative array containing spelling suggestions and offset data * @access private */ var $_suggestions; /** * @var int Length of checked text * @access private */ var $_chars; /** * @var string Language to check spelling for * @access private */ var $_lang; /** * @var bool Whether to consider run-rogether words like Wordpress valid * @access private */ var $_runTogether; /** * @var string Custom personal word list path * @access private */ var $_personal; /** * @var string Custom replacement list path * @access private */ var $_repl; /** * @var int Maximum number of suggestions to return * @access private */ var $_maxSuggestions; /** * @var bool Whether to use a custom main dictionary location * @access private */ var $_customDict; /** * @var string Custom main dictionary location * @access private */ var $_customDictLocation; /** * @var string Character set to use * @access private */ var $_charset; /** * @var string aspell executable path * @access private */ var $_aspellPath; /** * @var array ISO 639 language codes * @access private */ var $_languageCodes; /** * @var array supported languages * @access private */ var $_supportedLanguages; //}}} //{{{ public function GenericSpellChecker($text, &$options) /** * Decorates __construct for PHP4 compatibility * @see __construct() */ function GenericSpellChecker($text, &$options) { $this->__construct(); } //}}} //{{{ public function __construct($text, &$options) /** * @param int $text Text to check for spelling errors (can be HTML) * @param array &$options Array containing pairs "option"=>value, where options can be: * */ function __construct($text, &$options){ $this->_lang = "en"; $this->_runTogether = true; $this->_maxSuggestions = 5; $this->_html = $text; $this->_offsets = array(); $this->_suggestions = array(); $this->_charset = "utf-8"; $this->_supportedLanguages = array(); $this->_languageCodes = array ( //{{{ language codes, loooong list "aa" => "Afar", "ab" => "Abkhazian", "af" => "Afrikaans", "am" => "Amharic", "ar" => "Arabic", "as" => "Assamese", "ay" => "Aymara", "az" => "Azerbaijani", "ba" => "Bashkir", "be" => "Byelorussian", "bg" => "Bulgarian", "bh" => "Bihari", "bi" => "Bislama", "bn" => "Bengali; Bangla", "bo" => "Tibetan", "br" => "Breton", "ca" => "Catalan", "co" => "Corsican", "cs" => "Czech", "cy" => "Welsh", "da" => "Danish", "de" => "German", "dz" => "Bhutani", "el" => "Greek", "en" => "English", "eo" => "Esperanto", "es" => "Spanish", "et" => "Estonian", "eu" => "Basque", "fa" => "Persian", "fi" => "Finnish", "fj" => "Fiji", "fo" => "Faroese", "fr" => "French", "fy" => "Frisian", "ga" => "Irish", "gd" => "Scots Gaelic", "gl" => "Galician", "gn" => "Guarani", "gu" => "Gujarati", "ha" => "Hausa", "he" => "Hebrew", "hi" => "Hindi", "hr" => "Croatian", "hu" => "Hungarian", "hy" => "Armenian", "ia" => "Interlingua", "id" => "Indonesian", "ie" => "Interlingue", "ik" => "Inupiak", "is" => "Icelandic", "it" => "Italian", "iu" => "Inuktitut", "ja" => "Japanese", "jw" => "Javanese", "ka" => "Georgian", "kk" => "Kazakh", "kl" => "Greenlandic", "km" => "Cambodian", "kn" => "Kannada", "ko" => "Korean", "ks" => "Kashmiri", "ku" => "Kurdish", "ky" => "Kirghiz", "la" => "Latin", "ln" => "Lingala", "lo" => "Laothian", "lt" => "Lithuanian", "lv" => "Latvian, Lettish", "mg" => "Malagasy", "mi" => "Maori", "mk" => "Macedonian", "ml" => "Malayalam", "mn" => "Mongolian", "mo" => "Moldavian", "mr" => "Marathi", "ms" => "Malay", "mt" => "Maltese", "my" => "Burmese", "na" => "Nauru", "ne" => "Nepali", "nl" => "Dutch", "no" => "Norwegian", "oc" => "Occitan", "om" => "(Afan) Oromo", "or" => "Oriya", "pa" => "Punjabi", "pl" => "Polish", "ps" => "Pashto, Pushto", "pt" => "Portuguese", "qu" => "Quechua", "rm" => "Rhaeto-Romance", "rn" => "Kirundi", "ro" => "Romanian", "ru" => "Russian", "rw" => "Kinyarwanda", "sa" => "Sanskrit", "sd" => "Sindhi", "sg" => "Sangro", "sh" => "Serbo-Croatian", "si" => "Sinhalese", "sk" => "Slovak", "sl" => "Slovenian", "sm" => "Samoan", "sn" => "Shona", "so" => "Somali", "sq" => "Albanian", "sr" => "Serbian", "ss" => "Siswati", "st" => "Sesotho", "su" => "Sundanese", "sv" => "Swedish", "sw" => "Swahili", "ta" => "Tamil", "te" => "Telugu", "tg" => "Tajik", "th" => "Thai", "ti" => "Tigrinya", "tk" => "Turkmen", "tl" => "Tagalog", "tn" => "Setswana", "to" => "Tonga", "tr" => "Turkish", "ts" => "Tsonga", "tt" => "Tatar", "tw" => "Twi", "ug" => "Uighur", "uk" => "Ukrainian", "ur" => "Urdu", "uz" => "Uzbek", "vi" => "Vietnamese", "vo" => "Volapuk", "wo" => "Wolof", "xh" => "Xhosa", "yi" => "Yiddish", "yo" => "Yoruba", "za" => "Zhuang", "zh" => "Chinese", "zu" => "Zulu" //}}} ); foreach($options as $var => $value){ $var = "_$var"; $this->$var = $value; } mb_internal_encoding($this->_charset); mb_regex_encoding($this->_charset); mb_regex_set_options("z");//pcre syntax if($text) $this->_buildOffsetTable(); } //}}} //{{{ public abstract function checkSpelling() /** * Checks spelling of the supplied text and builds the suggestions array * @abstract * @access public */ function checkSpelling() { trigger_error(__CLASS__ . "::" . __FUNCTION__ . " is an abstract method, implementation required"); } //}}} //{{{ public abstract function storeReplacement() /** * Stores a replacement pair in the custom replacement list * @abstract * @access public */ function storeReplacement() { trigger_error(__CLASS__ . "::" . __FUNCTION__ . " is an abstract method, implementation required"); } //}}} //{{{ public abstract function addWord() /** * Adds a word to the word list * @abstract * @access public */ function addWord() { trigger_error(__CLASS__ . "::" . __FUNCTION__ . " is an abstract method, implementation required"); } //}}} //{{{ protected abstract function _buildSupportedLanguages() /** * Build the supported languages array * @abstract * @access protected */ function _buildSupportedLanguages() { trigger_error(__CLASS__ . "::" . __FUNCTION__ . " is an abstract method, implementation required"); } //}}} //{{{ public function toJSArray() /** * Returns a JavaScript object representation of the suggestions array * @return string * @access public */ function toJSArray() { $js = "new Array("; foreach($this->_suggestions as $sug){ $val = addslashes(join(",",$sug["value"])); $val = "'".str_replace(",","','",$val)."'"; //make strings javascript compatible $js .= "{o: $sug[o],l: $sug[l],s: $sug[s],value: new Array($val)},"; } $js = (count($this->_suggestions) > 0 ? substr($js,0,strlen($js)-1) : $js).")"; return $js; } //}}} //{{{ public function toPHPArray() /** * Returns the suggestions array * @return array * @access public */ function toPHPArray() { return $this->_suggestions; } //}}} //{{{ public function toXML() /** * Returns an XML representation of the suggestions array, compatible with * the Google toolbar spell checking service output * @return string * @access public */ function toXML(){ $xml = ''; foreach($this->_suggestions as $sug){ $xml .= "".join("\t",$sug["value"]).""; } $xml .= ''; return $xml; } //}}} //{{{ public function languageName() /** * Given a language code, return the language name * @param string $code ISO 639 language code * @return string|bool language name or false * @access public */ function languageName($code){ if(isset($this->_languageCodes[$code])) return $this->_languageCodes[$code]; return false; } //}}} //{{{ public function supportedLanguages() /** * Return an array containing available dictionaries * @return array * @access public */ function supportedLanguages(){ return $this->_supportedLanguages; } //}}} //{{{ protected function _updateOffsets() /** * Updates the offsets from the spell sugestions array to fit the input text * word positions * @access protected */ function _updateOffsets() { for($i = 0; $i < count($this->_suggestions); $i++) $this->_suggestions[$i]["o"] = $this->_offsets[$this->_suggestions[$i]["o"]]; } //}}} //{{{ private function _buildOffsetTable() /** * Creates the plain text → HTML offset translation table * @access private */ function _buildOffsetTable(){ $offsets = array(); $notag_offsets = array(); $off = 0; $offsets[] = 0; mb_ereg_search_init($this->_html,"((?:<[^>]+>)+|(?:&.+;)+)"); while(($word = @mb_ereg_search_pos())){ $word[0] = mb_strlen(mb_strcut($this->_html,0,$word[0])); //hack for a wirdness in mb_ereg_search_pos returning bad offsets $off += $word[1]; $offsets[] = $word[0] + $word[1]; $notag_offsets[] = $word[0] + $word[1] - $off; } $off = 0; $notag_offsets[] = 10000; $this->_chars = mb_ereg_search_getpos(); $cnt = 0; $oadd = -1; for($i = 0; $i < $this->_chars && $cnt < count($offsets); $i++){ if($i < $notag_offsets[$cnt]){ $oadd++; $this->_offsets[$i] = $oadd + $offsets[$cnt]; } else { $cnt++; $oadd = 0; $this->_offsets[$i] = $offsets[$cnt]; } } } //}}} } //}}} //{{{ class PspellSpellChecker /** * Spell checker class that uses the Pspell PHP library functions * @package AjaxSpellChecker * @subpackage WebService */ class PspellSpellChecker extends GenericSpellChecker { /** * Resource ID for the pspell dictionary link * @access private */ var $_pspell; //{{{ public function PspellSpellChecker($text, &$options) /** * Decorates __construct for PHP4 compatibility * @see __construct() */ function PspellSpellChecker($text, &$options) { $this->__construct($text, $options); } //}}} //{{{ public function __construct($text, &$options) /** * @see parent::__construct() */ function __construct($text, &$options) { parent::__construct($text, $options); $config = pspell_config_create($this->_lang, "", "", $this->_charset); pspell_config_mode($config, PSPELL_FAST); pspell_config_runtogether($config, $this->_runTogether); if($this->_personal) pspell_config_personal($config, $this->_personal); if($this->_repl) pspell_config_repl($config, $this->_repl); if($this->_customDict && function_exists("pspell_config_dict_dir")) pspell_config_dict_dir($this->_customDictLocation); $this->_pspell = pspell_new_config($config); if($text){ $this->checkSpelling(); } else { $this->_buildSupportedLanguages(); } } //}}} //{{{ public function checkSpelling() function checkSpelling() { $text = strip_tags($this->_html); $text = html_entity_decode($text); $text = mb_ereg_replace("[~&\"#{(\[_\\^@)\]=+,.;/:!%*[:space:][:blank:]]"," ", $text); $words = mb_split("\s", $text); $off = 0; foreach($words as $word) { $l = mb_strlen($word); if(!pspell_check($this->_pspell, $word)) { $sug = array_slice(pspell_suggest($this->_pspell, $word), 0, $this->_maxSuggestions); $o = $off; $s = 0; for($i = 0; $i < count($sug); $i++) { if(levenshtein($word,$sug[$i]) == 1) { $s = $i + 1; break; } } $this->_suggestions[] = array("o" => $o, "l" => $l, "s" => $s, "value" => $sug); } $off += ($l+1); } $this->_updateOffsets(); } //}}} //{{{ public function storeReplacement($wrong, $right) /** * @param string $wrong * @param string $right * * the replacement pair to be stored */ function storeReplacement($wrong, $right){ pspell_store_replacement($this->_pspell, $wrong, $right); pspell_save_wordlist($this->_pspell); } //}}} //{{{ public function addWord($word) /** * @param string $word the word to be added to custom word list */ function addWord($word){ pspell_add_to_personal($this->_pspell, $word); pspell_save_wordlist($this->_pspell); } //}}} //{{{ protected function _buildSupportedLanguages() /** * * Pspell provides no way of listing available dictionaries, so we need to do it the hard way. * Use of caching on the returned array is highly encouraged. */ function _buildSupportedLanguages() { foreach($this->_languageCodes as $lc=>$ln) { $tmp_config = pspell_config_create($lc); $tmp_link = @pspell_new_config($tmp_config); if($tmp_link !== false) $this->_supportedLanguages[$lc] = $ln; unset($tmp_config); unset($tmp_link); } } //}}} } //}}} //{{{ class AspellSpellChecker /** * Checks spelling by passing text to the aspell executable. * * Only suited for low traffic sites, as there is an aspell fork for every request * @package AjaxSpellChecker * @subpackage WebService */ class AspellSpellChecker extends GenericSpellChecker { //{{{ private properties /** * @var array Pipes for communication with aspell * @access private */ var $_pipes; /** * @var int aspell process resource ID * @access private */ var $_proc; //}}} //{{{ public function AspellSpellChecker($text, &$options) /** * Decorates __construct for PHP4 compatibility * @see __construct() */ function AspellSpellChecker($text, &$options) { $this->__construct($text, $options); } //}}} //{{{ public function __construct($text, &$options) /** * @see parent::__construct() */ function __construct($text, &$options) { parent::__construct($text, $options); $cmd = "{$this->_aspellPath} -a"; $cmd .= " --lang=" . escapeshellarg($this->_lang); $cmd .= " --sug-mode=fast"; if($this->_runTogether) $cmd .=" --run-together"; if($this->_personal) $cmd .= " --personal=" . escapeshellarg($this->_personal); if($this->_repl) $cmd .= " --save-repl --repl=" . escapeshellarg($this->_repl); if($this->_customDict) $cmd .= " --dict-dir=" . escapeshellarg($this->_customDictLocation); $desc = array( 0 => array("pipe","r"), 1 => array("pipe","w"), 2 => array("file","/dev/null","w")); $this->_proc = proc_open($cmd,$desc,$this->_pipes); if(!is_resource($this->_proc)) trigger_error("Problem running aspell"); $str = trim(fread($this->_pipes[1],8192)); stream_set_blocking($this->_pipes[1], false); if($text){ $this->checkSpelling(); $this->_updateOffsets(); } else { $this->_cleanUp(); $this->_buildSupportedLanguages(); } } //}}} //{{{ public function checkSpelling() function checkSpelling() { $text = strip_tags($this->_html); $text = html_entity_decode($text); $text = preg_replace("/[^[:alnum:]']/"," ",$text); $words = preg_split("/\s/", $text, -1, PREG_SPLIT_OFFSET_CAPTURE); foreach($words as $word){ fwrite($this->_pipes[0], $word[0]."\n"); fflush($this->_pipes[0]); $str = ""; usleep(100000); //it looks like stream_select is buggy in php4, returning too fast stream_select($read = array($this->_pipes[1]), $write = NULL, $except = NULL, 0, 200000); $str = trim(fread($this->_pipes[1],8192)); if(empty($str)) continue; $o = $word[1]; $l = strlen($word[0]); switch($str[0]) { case "#": $s = 0; $this->_suggestions[] = array("o" => $o, "l" => $l, "s" => $s, "value" => array()); break; case "&": preg_match("/^& \w+ [0-9]+ ([0-9]+):(.+)$/", $str, $matches); $s = $matches[1] + 1; $sug = array_slice(explode(", ",$matches[2]), 0, $this->_maxSuggestions); $this->_suggestions[] = array("o" => $o, "l" => $l, "s" => $s, "value" => $sug); break; default: continue; } $str = ""; } } //}}} //{{{ public function storeReplacement($wrong, $right) /** * @param string $wrong * @param string $right * * the replacement pair to be stored */ function storeReplacement($wrong, $right){ fwrite($this->_pipes[0], "\$\$ra $wrong,$right\n#\n"); fflush($this->_pipes[0]); $this->_cleanUp(); } //}}} //{{{ public function addWord($word) /** * @param string $word the word to be added to custom word list */ function addWord($word){ fwrite($this->_pipes[0], "*$word\n#\n"); fflush($this->_pipes[0]); $this->_cleanUp(); } //}}} //{{{ protected function _buildSupportedLanguages() function _buildSupportedLanguages() { $pipes = array(); $desc = array( 0 => array("pipe","r"), 1 => array("pipe","w"), 2 => array("file","/dev/null","w")); $cmd = "{$this->_aspellPath} dump dicts"; $proc = proc_open($cmd, $desc, $pipes); $str = ""; if(is_resource($proc)){ $str = trim(fread($pipes[1],8192)); $dicts = explode("\n", $str); foreach($dicts as $d){ $d = trim($d); if(strlen($d) == 2) { //keep only main language, no dialect/jargon etc $this->_supportedLanguages[$d] = $this->_languageCodes[$d]; } } } } //}}} //{{{ private function _cleanUp() method /** * Close pipes and end aspell process * @access private */ function _cleanUp() { fclose($this->_pipes[0]); fclose($this->_pipes[1]); proc_close($this->_proc); } //}}} } //}}} //{{{ class GoogleSpellChecker /** * Checks spelling using the google toolbar web service * @package AjaxSpellChecker * @subpackage WebService */ class GoogleSpellChecker extends GenericSpellChecker { //{{{ private variables /** * @var array google supported language codes * @access private */ var $_google_lang; //}}} //{{{ public function GoogleSpellChecker($text, &$options) /** * Decorates __construct for PHP4 compatibility * @see __construct() */ function GoogleSpellChecker($text, &$options) { $this->__construct($text, &$options); } //}}} //{{{ public function __construct($text, &$options) /** * @see parent::__construct() */ function __construct($text, &$options) { parent::__construct($text, $options); $this->_google_lang = array("da", "de", "en", "es", "fr", "it", "nl", "pl", "pt", "fi", "sv"); if(!in_array($this->_lang,$this->_google_lang)) $this->_lang = "en"; if($text){ $this->checkSpelling(); $this->_updateOffsets(); } else { $this->_buildSupportedLanguages(); } } //}}} //{{{ public function checkSpelling() function checkSpelling() { $words = strip_tags($this->_html); $words = html_entity_decode($words); $words = preg_replace("/[^[:alnum:]']/"," ",$words); $words = "" . $words . ""; $server = "www.google.com"; $port = 443; $path = "/tbproxy/spell?lang=".$this->_lang."&hl=".$_this->_lang; $host = "www.google.com"; $url = "https://" . $server; $page = $path; $post_string = $words; $header= "POST ".$page." HTTP/1.0 \r\n"; $header .= "MIME-Version: 1.0 \r\n"; $header .= "Content-type: application/PTI26 \r\n"; $header .= "Content-length: ".strlen($post_string)." \r\n"; $header .= "Content-transfer-encoding: text \r\n"; $header .= "Request-number: 1 \r\n"; $header .= "Document-type: Request \r\n"; $header .= "Interface-Version: Test 1.4 \r\n"; $header .= "Connection: close \r\n\r\n"; $header .= $post_string; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL,$url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_TIMEOUT, 120); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 60); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $header); $data = curl_exec($ch); if(curl_errno($ch)) error_log(curl_error($ch)); else curl_close($ch); $vals = array(); $index = array(); $xml_parser = xml_parser_create(); xml_parser_set_option($xml_parser,XML_OPTION_CASE_FOLDING,0); xml_parser_set_option($xml_parser,XML_OPTION_SKIP_WHITE,1); xml_parse_into_struct($xml_parser, $data, $vals, $index); xml_parser_free($xml_parser); if(is_array($index["c"])){ foreach($index["c"] as $idx){ $val = $vals[$idx]["value"]; $this->_suggestions[] = array_merge($vals[$idx]["attributes"], array("value" => explode("\t",$val))); } } } //}}} /** * Custom replacement lists not supported with google */ function storeReplacement($wrong, $right){ /* personal dictionaries not supported*/ } /** * Custom word lists not supported with google */ function addWord($word){ /* personal dictionaries not supported*/ } //{{{ protected function _buildSupportedLanguages() function _buildSupportedLanguages() { foreach($this->_google_lang as $l) $this->_supportedLanguages[$l] = $this->_languageCodes[$l]; } //}}} } //}}} //{{{ class SpellChecker /** * Factory class * * to get a spell checker with the default options: *

* speller = (new SpellChecker())->create($text);
* $suggestions_php = $speller->toPHPArray();
* $suggestions_js = $speller->toJSArray();
* $suggestions_xml = $speller->toXML();
* 
* * @package AjaxSpellChecker * @subpackage WebService */ class SpellChecker { //{{{ private properties /** * @var array options * @see GenericSpellChecker::__construct() * @access private */ var $_options; /** * @var array errors * @access private */ var $_err; /** * @var array supported backends * @access private */ var $_backends; //}}} //{{{ public function SpellChecker($params = array() /** * decorates __construct for PHP4 compatibility * @see __construct() */ function SpellChecker($params = array()) { $this->__construct($params); } //}}} //{{{ public function __construct($params = array()) /** * @param array $params * for params array contents, {@see GenericSpellChecker::__construct()} */ function __construct($params = array()) { $this->_options = $params; $this->_err = array(); $this->_backends = array("Pspell" => true, "Aspell" => true, "Google" => true); if(!is_readable($params["personal"]) && is_writable(dirname($params["personal"]))) { $fp = fopen($params["personal"],"w"); fwrite($fp,"personal_ws-1.1 $params[lang] 0\n"); fclose($fp); } if(!is_readable($params["repl"]) && is_writable(dirname($params["repl"]))) { $fp = fopen($params["repl"],"w"); fwrite($fp,"personal_repl-1.1 $params[lang] 0\n"); fclose($fp); } } //}}} //{{{ public function create($text, $backend = false) /** * Spell checker factory * * This functions checks for necessary features and selectd the spell * checking backend accordingly * @param string $text Text to check for spelling mistakes * @return object|bool a spell checker implementing the GenericSpellChecker interface or false */ function create($text, $backend = false) { if(!is_object($this)){ $factory = new SpellChecker(); return $factory->create($text, $backend); } //{{{ check for pspell if(!extension_loaded("pspell")){ $this->_err["Can't use Pspell"] = array("The pspell extension is not loaded"); $this->_backends["Pspell"] = false; } //}}} //{{{ check for the aspell executable $aspell_ok = true; $aspell_found = false; $tmp_err = array(); if(isset($this->_options["aspellPath"])) { if(!is_executable($this->_options["aspellPath"])){ $tmp_err[] = "Provided aspell does not exist or is not executable, trying to guess..."; } else { $aspell_found = true; } } else { $tmp_err[] = "Path to aspell not provided, trying to guess..."; } if(!$aspell_found){ $aspell_ok = false; $path = explode(":",$_ENV["PATH"]); foreach($path as $p){ $ap_unix = "$p/aspell"; $ap_win = "$p/aspell.exe"; if(is_executable($ap_unix)){ $this->_options["aspellPath"] = $ap_unix; $aspell_found = true; break; } if(is_executable($ap_win)){ $this->_options["aspellPath"] = $ap_win; $aspell_found = true; break; } } } if(!$aspell_found) $tmp_err[] = "No executable program called aspell or aspell.exe was found in PATH"; $aspell_ok = $aspell_found; if(!function_exists("proc_open")) { $tmp_err[] = "The proc_open() function doesn't exist"; $aspell_ok = false; } if(stristr(ini_get("disable_functions"),"proc_open") !== false) { $tmp_err[] = "The proc_open() function is disabled."; $aspell_ok = false; } if(!$aspell_ok){ $this->_err["Can't use aspell"] = $tmp_err; $this->_backends["Aspell"] = false; } //}}} //{{{ see if we can contact google $google_ok = true; $tmp_err = array(); if(!extension_loaded("curl")) { $google_ok = false; $tmp_err[] = "The curl extension is not loaded"; } if(!extension_loaded("xml")) { $google_ok = false; $tmp_err[] = "The xml extension is not loaded"; } if(stristr(ini_get("disable_functions"),"curl") !== false) { $google_ok = false; $tmp_err[] = "The curl functions are disabled"; } if(!$google_ok){ $this->_err["Can't use google"] = $tmp_err; $this->_backends["Google"] = false; } //}}} if($backend && $this->_backends[$backend]) { $class = "{$backend}SpellChecker"; return new $class($text, $this->_options); } foreach($this->_backends as $b=>$v){ if($v){ $class = "{$b}SpellChecker"; return new $class($text, $this->_options); } } return false; } //}}} //{{{ public function errorLog() /** * Return an array containing errors encountered. * * The array format is array("error"=>array("reason","reason",...),...) * @return array */ function errorLog() { return $this->_err; } //}}} //{{{ public function backends() /** * Return an array containing supported backends and their availability status * @return array */ function backends() { return $this->_backends; } //}}} } //}}} ?>