00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00032 require_once(PATH_tslib.'class.tslib_pibase.php');
00033
00034 class tx_rtehtmlarea_pi1 extends tslib_pibase {
00035
00041 var $cObj;
00042 var $prefixId = 'tx_rtehtmlarea_pi1';
00043 var $scriptRelPath = 'pi1/class.tx_rtehtmlarea_pi1.php';
00044 var $extKey = 'rtehtmlarea';
00045 var $conf = array();
00046 var $siteUrl;
00047 var $charset = 'utf-8';
00048 var $parserCharset = 'utf-8';
00049 var $defaultAspellEncoding = 'utf-8';
00050 var $aspellEncoding;
00051 var $result;
00052 var $text;
00053 var $misspelled = array();
00054 var $suggestedWords;
00055 var $wordCount = 0;
00056 var $suggestionCount = 0;
00057 var $suggestedWordCount = 0;
00058 var $pspell_link;
00059 var $pspellMode = 'normal';
00060 var $dictionary;
00061 var $AspellDirectory;
00062 var $pspell_is_available;
00063 var $forceCommandMode = 0;
00064 var $filePrefix = 'rtehtmlarea_';
00065 var $uploadFolder = 'uploads/tx_rtehtmlarea/';
00066 var $userUid;
00067 var $personalDictsArg = '';
00068 var $xmlCharacterData = '';
00069
00077 function main($conf) {
00078 global $TYPO3_CONF_VARS, $TYPO3_DB;
00079
00080 $this->conf = $conf;
00081 $this->tslib_pibase();
00082 $this->pi_setPiVarDefaults();
00083 $this->pi_loadLL();
00084 $this->pi_USER_INT_obj = 1;
00085
00086 $time_start = microtime(true);
00087 $this->pspell_is_available = in_array('pspell', get_loaded_extensions());
00088 $this->AspellDirectory = trim($TYPO3_CONF_VARS['EXTCONF'][$this->extKey]['AspellDirectory'])? trim($TYPO3_CONF_VARS['EXTCONF'][$this->extKey]['AspellDirectory']) : '/usr/bin/aspell';
00089 $this->forceCommandMode = (trim($TYPO3_CONF_VARS['EXTCONF'][$this->extKey]['forceCommandMode']))? trim($TYPO3_CONF_VARS['EXTCONF'][$this->extKey]['forceCommandMode']) : 0;
00090 $safe_mode_is_enabled = ini_get('safe_mode');
00091 if($safe_mode_is_enabled && !$this->pspell_is_available ) echo('Configuration problem: Spell checking cannot be performed');
00092 if($safe_mode_is_enabled && $this->forceCommandMode) echo('Configuration problem: Spell checking cannot be performed in command mode');
00093 if(!$safe_mode_is_enabled && (!$this->pspell_is_available || $this->forceCommandMode)) {
00094 $AspellVersionString = explode('Aspell', shell_exec( $this->AspellDirectory.' -v'));
00095 $AspellVersion = substr( $AspellVersionString[1], 0, 4);
00096 if( doubleval($AspellVersion) < doubleval('0.5') && (!$this->pspell_is_available || $this->forceCommandMode)) echo('Configuration problem: Aspell version ' . $AspellVersion . ' too old. Spell checking cannot be performed in command mode');
00097 $this->defaultAspellEncoding = trim(shell_exec($this->AspellDirectory.' config encoding'));
00098 }
00099
00100
00101 if(!$safe_mode_is_enabled && (!$this->pspell_is_available || $this->forceCommandMode)) {
00102 $dictionaryList = shell_exec( $this->AspellDirectory.' dump dicts');
00103 $dictionaryList = implode(',', t3lib_div::trimExplode(chr(10), $dictionaryList, 1));
00104 }
00105 if( empty($dictionaryList) ) {
00106 $dictionaryList = trim($TYPO3_CONF_VARS['EXTCONF'][$this->extKey]['dictionaryList']);
00107 }
00108 if( empty($dictionaryList) ) {
00109 $dictionaryList = 'en';
00110 }
00111 $dictionaryArray = t3lib_div::trimExplode(',', $dictionaryList, 1);
00112
00113 $defaultDictionary = trim($TYPO3_CONF_VARS['EXTCONF'][$this->extKey]['defaultDictionary']);
00114 if(!$defaultDictionary || !in_array($defaultDictionary, $dictionaryArray)) {
00115 $defaultDictionary = 'en';
00116 }
00117
00118
00119 $languageArray = array();
00120 $tableA = 'sys_language';
00121 $tableB = 'static_languages';
00122 $selectFields = $tableA . '.uid,' . $tableB . '.lg_iso_2,' . $tableB . '.lg_country_iso_2';
00123 $table = $tableA . ' LEFT JOIN ' . $tableB . ' ON ' . $tableA . '.static_lang_isocode=' . $tableB . '.uid';
00124 $whereClause = '1=1 ';
00125 $whereClause .= ' AND ' . $tableA . '.hidden != 1';
00126 $res = $TYPO3_DB->exec_SELECTquery($selectFields, $table, $whereClause);
00127 while($row = $TYPO3_DB->sql_fetch_assoc($res)) {
00128 $languageArray[] = strtolower($row['lg_iso_2']).($row['lg_country_iso_2']?'_'.$row['lg_country_iso_2']:'');
00129 }
00130 if(!in_array($defaultDictionary, $languageArray)) {
00131 $languageArray[] = $defaultDictionary;
00132 }
00133 foreach ($dictionaryArray as $key => $dict) {
00134 $lang = explode('-', $dict);
00135 if( !in_array(substr($dict, 0, 2), $languageArray) || !empty($lang[1])) {
00136 unset($dictionaryArray[$key]);
00137 } else {
00138 $dictionaryArray[$key] = $lang[0];
00139 }
00140 }
00141 uasort($dictionaryArray, 'strcoll');
00142 $dictionaryList = implode(',', $dictionaryArray);
00143
00144
00145 $this->dictionary = t3lib_div::_POST('dictionary');
00146 if( empty($this->dictionary) || !in_array($this->dictionary, $dictionaryArray)) {
00147 $this->dictionary = $defaultDictionary;
00148 }
00149 $dictionaries = substr_replace($dictionaryList, '@'.$this->dictionary, strpos($dictionaryList, $this->dictionary), strlen($this->dictionary));
00150
00151
00152 $this->pspellMode = t3lib_div::_POST('pspell_mode')?t3lib_div::_POST('pspell_mode'): $this->pspellMode;
00153
00154 $this->pspellMode = t3lib_div::inList('ultra,fast,normal,bad-spellers',$this->pspellMode)?$this->pspellMode:'normal';
00155 switch($this->pspellMode) {
00156 case 'ultra':
00157 case 'fast':
00158 $pspellModeFlag = PSPELL_FAST;
00159 break;
00160 case 'bad-spellers':
00161 $pspellModeFlag = PSPELL_BAD_SPELLERS;
00162 break;
00163 case 'normal':
00164 default:
00165 $pspellModeFlag = PSPELL_NORMAL;
00166 break;
00167 }
00168
00169
00170 if (t3lib_div::_POST('pspell_charset')) {
00171 $this->charset = trim(t3lib_div::_POST('pspell_charset'));
00172 }
00173 if (strtolower($this->charset) == 'iso-8859-1') {
00174 $this->parserCharset = strtolower($this->charset);
00175 }
00176 $internal_encoding = mb_internal_encoding(strtoupper($this->parserCharset));
00177 $regex_encoding = mb_regex_encoding(strtoupper($this->parserCharset));
00178
00179
00180 $this->aspellEncoding = $this->parserCharset;
00181 if ($this->parserCharset == 'iso-8859-1' && strstr($this->defaultAspellEncoding, '8859-1')) {
00182 $this->aspellEncoding = $this->defaultAspellEncoding;
00183 }
00184
00185
00186 if($this->pspell_is_available && !$this->forceCommandMode) {
00187 $this->pspell_link = pspell_new($this->dictionary, '', '', $this->parserCharset, $pspellModeFlag);
00188 }
00189
00190
00191 if (t3lib_div::_POST('enablePersonalDicts') == 'true' && $GLOBALS['TSFE']->beUserLogin) {
00192 $this->userUid = 'BE_' . $GLOBALS['BE_USER']->user['uid'];
00193 if ($this->userUid) {
00194 $this->personalDictPath = t3lib_div::getFileAbsFileName($this->uploadFolder . $this->userUid);
00195 if (!is_dir($this->personalDictPath)) {
00196 t3lib_div::mkdir($this->personalDictPath);
00197 }
00198
00199 $this->personalDictsArg = ' --home-dir=' . escapeshellarg($this->personalDictPath);
00200 }
00201 }
00202
00203 $cmd = t3lib_div::_POST('cmd');
00204 if ($cmd == 'learn' && !$safe_mode_is_enabled) {
00205
00206 if(!$GLOBALS['TSFE']->beUserLogin) die('');
00207
00208 $to_p_dict = t3lib_div::_POST('to_p_dict');
00209 $to_p_dict = $to_p_dict ? $to_p_dict : array();
00210 $to_r_list = t3lib_div::_POST('to_r_list');
00211 $to_r_list = $to_r_list ? $to_r_list : array();
00212 header('Content-Type: text/plain; charset=' . strtoupper($this->parserCharset));
00213 header('Pragma: no-cache');
00214
00215 if($to_p_dict || $to_r_list) {
00216 $tmpFileName = t3lib_div::tempnam($this->filePrefix);
00217 if($filehandle = fopen($tmpFileName,'wb')) {
00218 foreach ($to_p_dict as $personal_word) {
00219 $cmd = '&' . $personal_word . "\n";
00220 echo $cmd;
00221 fwrite($filehandle, $cmd, strlen($cmd));
00222 }
00223 foreach ($to_r_list as $replace_pair) {
00224 $cmd = '$$ra ' . $replace_pair[0] . ' , ' . $replace_pair[1] . "\n";
00225 echo $cmd;
00226 fwrite($filehandle, $cmd, strlen($cmd));
00227 }
00228 $cmd = "#\n";
00229 echo $cmd;
00230 fwrite($filehandle, $cmd, strlen($cmd));
00231 fclose($filehandle);
00232
00233 $AspellCommand = 'cat ' . escapeshellarg($tmpFileName) . ' | ' . $this->AspellDirectory . ' -a --mode=none' . $this->personalDictsArg . ' --lang=' . escapeshellarg($this->dictionary) . ' --encoding=' . escapeshellarg($this->aspellEncoding) . ' 2>&1';
00234 print $AspellCommand . "\n";
00235 print shell_exec($AspellCommand);
00236 t3lib_div::unlink_tempfile($tmpFileName);
00237 echo('Personal word list was updated.');
00238 } else {
00239 echo('SpellChecker tempfile open error.');
00240 }
00241 } else {
00242 echo('Nothing to add to the personal word list.');
00243 }
00244 flush();
00245 exit();
00246 } else {
00247
00248
00249 $this->result = '<?xml version="1.0" encoding="' . $this->parserCharset . '"?>
00250 <!DOCTYPE html
00251 PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
00252 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
00253 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="' . substr($this->dictionary, 0, 2) . '" lang="' . substr($this->dictionary, 0, 2) . '">
00254 <html>
00255 <head>
00256 <meta http-equiv="Content-Type" content="text/html; charset=' . $this->parserCharset . '" />
00257 <link rel="stylesheet" type="text/css" media="all" href="spell-check-style.css" />
00258 <script type="text/javascript">
00259 /*<![CDATA[*/
00260 <!--
00261 ';
00262
00263
00264 $content = t3lib_div::_POST('content');
00265
00266
00267 $parser = xml_parser_create(strtoupper($this->parserCharset));
00268 xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
00269 xml_set_object($parser, &$this);
00270 if (!xml_set_element_handler($parser, 'startHandler', 'endHandler')) echo('Bad xml handler setting');
00271 if (!xml_set_character_data_handler($parser, 'collectDataHandler')) echo('Bad xml handler setting');
00272 if (!xml_set_default_handler($parser, 'defaultHandler')) echo('Bad xml handler setting');
00273 if (!xml_parse($parser,'<?xml version="1.0" encoding="' . $this->parserCharset . '"?><spellchecker> ' . mb_ereg_replace(' ', ' ', $content) . ' </spellchecker>')) echo('Bad parsing');
00274 if (xml_get_error_code($parser)) {
00275 die('Line '.xml_get_current_line_number($parser).': '.xml_error_string(xml_get_error_code($parser)));
00276 }
00277 xml_parser_free($parser);
00278 if ($this->pspell_is_available && !$this->forceCommandMode) {
00279 pspell_clear_session ($this->pspell_link);
00280 }
00281 $this->result .= 'var suggested_words = {' . $this->suggestedWords . '};
00282 ';
00283
00284
00285 $time = number_format(microtime(true) - $time_start, 2, ',', ' ');
00286
00287
00288 $this->result .= 'var spellcheck_info = { "Total words":"'.$this->wordCount.'","Misspelled words":"'.sizeof($this->misspelled).'","Total suggestions":"'.$this->suggestionCount.'","Total words suggested":"'.$this->suggestedWordCount.'","Spelling checked in":"'.$time.'" };
00289 // -->
00290 /*]]>*/
00291 </script>
00292 </head>
00293 ';
00294 $this->result .= '<body onload="window.parent.finishedSpellChecking();">';
00295 $this->result .= preg_replace('/'.preg_quote('<?xml').'.*'.preg_quote('?>').'['.preg_quote(chr(10).chr(13).chr(32)).']*/', '', $this->text);
00296 $this->result .= '<div id="HA-spellcheck-dictionaries">'.$dictionaries.'</div>';
00297
00298
00299 $this->result .= '
00300 </body></html>';
00301
00302
00303 header('Content-Type: text/html; charset=' . strtoupper($this->parserCharset));
00304 echo $this->result;
00305 }
00306
00307 }
00308
00309 function startHandler($xml_parser, $tag, $attributes) {
00310 if (strlen($this->xmlCharacterData)) {
00311 $this->spellCheckHandler($xml_parser, $this->xmlCharacterData);
00312 $this->xmlCharacterData = '';
00313 }
00314
00315 switch($tag) {
00316 case 'spellchecker':
00317 break;
00318 case 'br':
00319 case 'BR':
00320 case 'img':
00321 case 'IMG':
00322 case 'hr':
00323 case 'HR':
00324 case 'area':
00325 case 'AREA':
00326 $this->text .= '<'. mb_strtolower($tag) . ' ';
00327 foreach( $attributes as $key => $val) {
00328 $this->text .= $key . '="' . $val . '" ';
00329 }
00330 $this->text .= ' />';
00331 break;
00332 default:
00333 $this->text .= '<'. mb_strtolower($tag) . ' ';
00334 foreach( $attributes as $key => $val) {
00335 $this->text .= $key . '="' . $val . '" ';
00336 }
00337 $this->text .= '>';
00338 break;
00339 }
00340 return;
00341 }
00342
00343 function endHandler($xml_parser, $tag) {
00344 if (strlen($this->xmlCharacterData)) {
00345 $this->spellCheckHandler($xml_parser, $this->xmlCharacterData);
00346 $this->xmlCharacterData = '';
00347 }
00348
00349 switch($tag) {
00350 case 'spellchecker':
00351 break;
00352 case 'br':
00353 case 'BR':
00354 case 'img':
00355 case 'IMG':
00356 case 'hr':
00357 case 'HR':
00358 case 'input':
00359 case 'INPUT':
00360 case 'area':
00361 case 'AREA':
00362 break;
00363 default:
00364 $this->text .= '</' . $tag . '>';
00365 break;
00366 }
00367 return;
00368 }
00369
00370 function spellCheckHandler($xml_parser, $string) {
00371 $incurrent=array();
00372 $stringText = $string;
00373 $words = mb_split('\W+', $stringText);
00374 while( list(,$word) = each($words) ) {
00375 $word = mb_ereg_replace(' ', '', $word);
00376 if( $word && !is_numeric($word)) {
00377 if($this->pspell_is_available && !$this->forceCommandMode) {
00378 if (!pspell_check($this->pspell_link, $word)) {
00379 if(!in_array($word, $this->misspelled)) {
00380 if(sizeof($this->misspelled) != 0 ) {
00381 $this->suggestedWords .= ',';
00382 }
00383 $suggest = array();
00384 $suggest = pspell_suggest($this->pspell_link, $word);
00385 if(sizeof($suggest) != 0 ) {
00386 $this->suggestionCount++;
00387 $this->suggestedWordCount += sizeof($suggest);
00388 }
00389 $this->suggestedWords .= '"'.$word.'":"'.implode(',',$suggest).'"';
00390 $this->misspelled[] = $word;
00391 unset($suggest);
00392 }
00393 if( !in_array($word, $incurrent) ) {
00394 $stringText = mb_ereg_replace('\b'.$word.'\b', '<span class="HA-spellcheck-error">'.$word.'</span>', $stringText);
00395 $incurrent[] = $word;
00396 }
00397 }
00398 } else {
00399 $tmpFileName = t3lib_div::tempnam($this->filePrefix);
00400 if(!$filehandle = fopen($tmpFileName,'wb')) echo('SpellChecker tempfile open error');
00401 if(!fwrite($filehandle, $word)) echo('SpellChecker tempfile write error');
00402 if(!fclose($filehandle)) echo('SpellChecker tempfile close error');
00403 $AspellCommand = 'cat ' . escapeshellarg($tmpFileName) . ' | ' . $this->AspellDirectory . ' -a check --mode=none --sug-mode=' . escapeshellarg($this->pspellMode) . $this->personalDictsArg . ' --lang=' . escapeshellarg($this->dictionary) . ' --encoding=' . escapeshellarg($this->aspellEncoding) . ' 2>&1';
00404 $AspellAnswer = shell_exec($AspellCommand);
00405 $AspellResultLines = array();
00406 $AspellResultLines = t3lib_div::trimExplode(chr(10), $AspellAnswer, 1);
00407 if(substr($AspellResultLines[0],0,6) == 'Error:') echo("{$AspellAnswer}");
00408 t3lib_div::unlink_tempfile($tmpFileName);
00409 if(substr($AspellResultLines['1'],0,1) != '*') {
00410 if(!in_array($word, $this->misspelled)) {
00411 if(sizeof($this->misspelled) != 0 ) {
00412 $this->suggestedWords .= ',';
00413 }
00414 $suggest = array();
00415 $suggestions = array();
00416 if (substr($AspellResultLines['1'],0,1) == '&') {
00417 $suggestions = t3lib_div::trimExplode(':', $AspellResultLines['1'], 1);
00418 $suggest = t3lib_div::trimExplode(',', $suggestions['1'], 1);
00419 }
00420 if (sizeof($suggest) != 0) {
00421 $this->suggestionCount++;
00422 $this->suggestedWordCount += sizeof($suggest);
00423 }
00424 $this->suggestedWords .= '"'.$word.'":"'.implode(',',$suggest).'"';
00425 $this->misspelled[] = $word;
00426 unset($suggest);
00427 unset($suggestions);
00428 }
00429 if (!in_array($word, $incurrent)) {
00430 $stringText = mb_ereg_replace('\b'.$word.'\b', '<span class="HA-spellcheck-error">'.$word.'</span>', $stringText);
00431 $incurrent[] = $word;
00432 }
00433 }
00434 unset($AspellResultLines);
00435 }
00436 $this->wordCount++;
00437 }
00438 }
00439 $this->text .= $stringText;
00440 unset($incurrent);
00441 return;
00442 }
00443
00444 function collectDataHandler($xml_parser, $string) {
00445 $this->xmlCharacterData .= $string;
00446 }
00447
00448 function defaultHandler($xml_parser, $string) {
00449 $this->text .= $string;
00450 return;
00451 }
00452
00453 }
00454
00455 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/rtehtmlarea/pi1/class.tx_rtehtmlarea_pi1.php']) {
00456 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/rtehtmlarea/pi1/class.tx_rtehtmlarea_pi1.php']);
00457 }
00458
00459 ?>