|
TYPO3 API
SVNRelease
|
00001 <?php 00002 /*************************************************************** 00003 * Copyright notice 00004 * 00005 * (c) 2003-2011 Stanislas Rolland <typo3(arobas)sjbr.ca> 00006 * All rights reserved 00007 * 00008 * This script is part of the Typo3 project. The Typo3 project is 00009 * free software; you can redistribute it and/or modify 00010 * it under the terms of the GNU General Public License as published by 00011 * the Free Software Foundation; either version 2 of the License, or 00012 * (at your option) any later version. 00013 * 00014 * The GNU General Public License can be found at 00015 * http://www.gnu.org/copyleft/gpl.html. 00016 * 00017 * This script is distributed in the hope that it will be useful, 00018 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00019 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00020 * GNU General Public License for more details. 00021 * 00022 * This copyright notice MUST APPEAR in all copies of the script! 00023 ***************************************************************/ 00024 /** 00025 * Spell checking plugin 'tx_rtehtmlarea_pi1' for the htmlArea RTE extension. 00026 * 00027 * @author Stanislas Rolland <typo3(arobas)sjbr.ca> 00028 * 00029 * TYPO3 SVN ID: $Id: class.tx_rtehtmlarea_pi1.php 10450 2011-02-12 00:00:20Z stan $ 00030 * 00031 */ 00032 00033 class tx_rtehtmlarea_pi1 { 00034 00035 protected $csConvObj; 00036 var $extKey = 'rtehtmlarea'; // The extension key. 00037 var $siteUrl; 00038 var $charset = 'utf-8'; 00039 var $parserCharset = 'utf-8'; 00040 var $defaultAspellEncoding = 'utf-8'; 00041 var $aspellEncoding; 00042 var $result; 00043 var $text; 00044 var $misspelled = array(); 00045 var $suggestedWords; 00046 var $wordCount = 0; 00047 var $suggestionCount = 0; 00048 var $suggestedWordCount = 0; 00049 var $pspell_link; 00050 var $pspellMode = 'normal'; 00051 var $dictionary; 00052 var $AspellDirectory; 00053 var $pspell_is_available; 00054 var $forceCommandMode = 0; 00055 var $filePrefix = 'rtehtmlarea_'; 00056 var $uploadFolder = 'uploads/tx_rtehtmlarea/'; 00057 var $userUid; 00058 var $personalDictsArg = ''; 00059 var $xmlCharacterData = ''; 00060 00061 /** 00062 * Main class of Spell Checker plugin for Typo3 CMS 00063 * 00064 * @return string content produced by the plugin 00065 */ 00066 function main() { 00067 00068 $this->csConvObj = t3lib_div::makeInstance('t3lib_cs'); 00069 00070 // Setting start time 00071 $time_start = microtime(true); 00072 $this->pspell_is_available = in_array('pspell', get_loaded_extensions()); 00073 $this->AspellDirectory = trim($GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][$this->extKey]['plugins']['SpellChecker']['AspellDirectory'])? trim($GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][$this->extKey]['plugins']['SpellChecker']['AspellDirectory']) : '/usr/bin/aspell'; 00074 $this->forceCommandMode = (trim($GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][$this->extKey]['plugins']['SpellChecker']['forceCommandMode']))? trim($GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][$this->extKey]['plugins']['SpellChecker']['forceCommandMode']) : 0; 00075 $safe_mode_is_enabled = t3lib_utility_PhpOptions::isSafeModeEnabled(); 00076 if($safe_mode_is_enabled && !$this->pspell_is_available ) echo('Configuration problem: Spell checking cannot be performed'); 00077 if($safe_mode_is_enabled && $this->forceCommandMode) echo('Configuration problem: Spell checking cannot be performed in command mode'); 00078 if(!$safe_mode_is_enabled && (!$this->pspell_is_available || $this->forceCommandMode)) { 00079 $AspellVersionString = explode('Aspell', shell_exec( $this->AspellDirectory.' -v')); 00080 $AspellVersion = substr( $AspellVersionString[1], 0, 4); 00081 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'); 00082 $this->defaultAspellEncoding = trim(shell_exec($this->AspellDirectory.' config encoding')); 00083 } 00084 00085 // Setting the list of dictionaries 00086 if (!$safe_mode_is_enabled && (!$this->pspell_is_available || $this->forceCommandMode)) { 00087 $dictionaryList = shell_exec( $this->AspellDirectory.' dump dicts'); 00088 $dictionaryList = implode(',', t3lib_div::trimExplode(LF, $dictionaryList, 1)); 00089 } 00090 if (empty($dictionaryList)) { 00091 $dictionaryList = t3lib_div::_POST('showDictionaries'); 00092 } 00093 $dictionaryArray = t3lib_div::trimExplode(',', $dictionaryList, 1); 00094 $restrictToDictionaries = t3lib_div::_POST('restrictToDictionaries'); 00095 if ($restrictToDictionaries) { 00096 $dictionaryArray = array_intersect($dictionaryArray, t3lib_div::trimExplode(',', $restrictToDictionaries, 1)); 00097 } 00098 if (!count($dictionaryArray)) { 00099 $dictionaryArray[] = 'en'; 00100 } 00101 $this->dictionary = t3lib_div::_POST('dictionary'); 00102 $defaultDictionary = $this->dictionary; 00103 if (!$defaultDictionary || !in_array($defaultDictionary, $dictionaryArray)) { 00104 $defaultDictionary = 'en'; 00105 } 00106 uasort($dictionaryArray, 'strcoll'); 00107 $dictionaryList = implode(',', $dictionaryArray); 00108 // Setting the dictionary 00109 if (empty($this->dictionary) || !in_array($this->dictionary, $dictionaryArray)) { 00110 $this->dictionary = 'en'; 00111 } 00112 // Setting the pspell suggestion mode 00113 $this->pspellMode = t3lib_div::_POST('pspell_mode')?t3lib_div::_POST('pspell_mode'): $this->pspellMode; 00114 // Now sanitize $this->pspellMode 00115 $this->pspellMode = t3lib_div::inList('ultra,fast,normal,bad-spellers',$this->pspellMode)?$this->pspellMode:'normal'; 00116 switch($this->pspellMode) { 00117 case 'ultra': 00118 case 'fast': 00119 $pspellModeFlag = PSPELL_FAST; 00120 break; 00121 case 'bad-spellers': 00122 $pspellModeFlag = PSPELL_BAD_SPELLERS; 00123 break; 00124 case 'normal': 00125 default: 00126 $pspellModeFlag = PSPELL_NORMAL; 00127 break; 00128 } 00129 00130 // Setting the charset 00131 if (t3lib_div::_POST('pspell_charset')) { 00132 $this->charset = trim(t3lib_div::_POST('pspell_charset')); 00133 } 00134 if (strtolower($this->charset) == 'iso-8859-1') { 00135 $this->parserCharset = strtolower($this->charset); 00136 } 00137 00138 // In some configurations, Aspell uses 'iso8859-1' instead of 'iso-8859-1' 00139 $this->aspellEncoding = $this->parserCharset; 00140 if ($this->parserCharset == 'iso-8859-1' && strstr($this->defaultAspellEncoding, '8859-1')) { 00141 $this->aspellEncoding = $this->defaultAspellEncoding; 00142 } 00143 00144 // However, we are going to work only in the parser charset 00145 if($this->pspell_is_available && !$this->forceCommandMode) { 00146 $this->pspell_link = pspell_new($this->dictionary, '', '', $this->parserCharset, $pspellModeFlag); 00147 } 00148 00149 // Setting the path to user personal dicts, if any 00150 if (t3lib_div::_POST('enablePersonalDicts') == 'true' && TYPO3_MODE == 'BE' && is_object($GLOBALS['BE_USER'])) { 00151 $this->userUid = 'BE_' . $GLOBALS['BE_USER']->user['uid']; 00152 if ($this->userUid) { 00153 $this->personalDictPath = t3lib_div::getFileAbsFileName($this->uploadFolder . $this->userUid); 00154 if (!is_dir($this->personalDictPath)) { 00155 t3lib_div::mkdir($this->personalDictPath); 00156 } 00157 // escape here for later use 00158 $this->personalDictsArg = ' --home-dir=' . escapeshellarg($this->personalDictPath); 00159 } 00160 } 00161 00162 $cmd = t3lib_div::_POST('cmd'); 00163 if ($cmd == 'learn' && !$safe_mode_is_enabled) { 00164 // Only availble for BE_USERS, die silently if someone has gotten here by accident 00165 if (TYPO3_MODE !='BE' || !is_object($GLOBALS['BE_USER'])) die(''); 00166 // Updating the personal word list 00167 $to_p_dict = t3lib_div::_POST('to_p_dict'); 00168 $to_p_dict = $to_p_dict ? $to_p_dict : array(); 00169 $to_r_list = t3lib_div::_POST('to_r_list'); 00170 $to_r_list = $to_r_list ? $to_r_list : array(); 00171 header('Content-Type: text/plain; charset=' . strtoupper($this->parserCharset)); 00172 header('Pragma: no-cache'); 00173 if($to_p_dict || $to_r_list) { 00174 $tmpFileName = t3lib_div::tempnam($this->filePrefix); 00175 if($filehandle = fopen($tmpFileName,'wb')) { 00176 foreach ($to_p_dict as $personal_word) { 00177 $cmd = '&' . $personal_word . LF; 00178 echo $cmd; 00179 fwrite($filehandle, $cmd, strlen($cmd)); 00180 } 00181 foreach ($to_r_list as $replace_pair) { 00182 $cmd = '$$ra ' . $replace_pair[0] . ' , ' . $replace_pair[1] . LF; 00183 echo $cmd; 00184 fwrite($filehandle, $cmd, strlen($cmd)); 00185 } 00186 $cmd = "#\n"; 00187 echo $cmd; 00188 fwrite($filehandle, $cmd, strlen($cmd)); 00189 fclose($filehandle); 00190 // $this->personalDictsArg has already been escapeshellarg()'ed above, it is an optional paramter and might be empty here 00191 $AspellCommand = 'cat ' . escapeshellarg($tmpFileName) . ' | ' . $this->AspellDirectory . ' -a --mode=none' . $this->personalDictsArg . ' --lang=' . escapeshellarg($this->dictionary) . ' --encoding=' . escapeshellarg($this->aspellEncoding) . ' 2>&1'; 00192 print $AspellCommand . LF; 00193 print shell_exec($AspellCommand); 00194 t3lib_div::unlink_tempfile($tmpFileName); 00195 echo('Personal word list was updated.'); 00196 } else { 00197 echo('SpellChecker tempfile open error.'); 00198 } 00199 } else { 00200 echo('Nothing to add to the personal word list.'); 00201 } 00202 flush(); 00203 exit(); 00204 } else { 00205 // Check spelling content 00206 // Initialize output 00207 $this->result = '<?xml version="1.0" encoding="' . $this->parserCharset . '"?> 00208 <!DOCTYPE html 00209 PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 00210 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 00211 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="' . substr($this->dictionary, 0, 2) . '" lang="' . substr($this->dictionary, 0, 2) . '"> 00212 <head> 00213 <meta http-equiv="Content-Type" content="text/html; charset=' . $this->parserCharset . '" /> 00214 <link rel="stylesheet" type="text/css" media="all" href="' . (TYPO3_MODE == 'BE' ? '../' : '') . t3lib_extMgm::siteRelPath($this->extKey) . '/htmlarea/plugins/SpellChecker/spell-check-style.css" /> 00215 <script type="text/javascript"> 00216 /*<![CDATA[*/ 00217 <!-- 00218 '; 00219 00220 // Getting the input content 00221 $content = t3lib_div::_POST('content'); 00222 00223 // Parsing the input HTML 00224 $parser = xml_parser_create(strtoupper($this->parserCharset)); 00225 xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0); 00226 xml_set_object($parser, $this); 00227 if (!xml_set_element_handler($parser, 'startHandler', 'endHandler')) echo('Bad xml handler setting'); 00228 if (!xml_set_character_data_handler($parser, 'collectDataHandler')) echo('Bad xml handler setting'); 00229 if (!xml_set_default_handler($parser, 'defaultHandler')) echo('Bad xml handler setting'); 00230 if (!xml_parse($parser,'<?xml version="1.0" encoding="' . $this->parserCharset . '"?><spellchecker> ' . preg_replace('/ /'.(($this->parserCharset == 'utf-8')?'u':''), ' ', $content) . ' </spellchecker>')) echo('Bad parsing'); 00231 if (xml_get_error_code($parser)) { 00232 die('Line '.xml_get_current_line_number($parser).': '.xml_error_string(xml_get_error_code($parser))); 00233 } 00234 xml_parser_free($parser); 00235 if ($this->pspell_is_available && !$this->forceCommandMode) { 00236 pspell_clear_session ($this->pspell_link); 00237 } 00238 $this->result .= 'var suggestedWords = {' . $this->suggestedWords . '}; 00239 var dictionaries = "' . $dictionaryList . '"; 00240 var selectedDictionary = "' . $this->dictionary . '"; 00241 '; 00242 00243 // Calculating parsing and spell checkting time 00244 $time = number_format(microtime(true) - $time_start, 2, ',', ' '); 00245 00246 // Insert spellcheck info 00247 $this->result .= 'var spellcheckInfo = { "Total words":"'.$this->wordCount.'","Misspelled words":"'.sizeof($this->misspelled).'","Total suggestions":"'.$this->suggestionCount.'","Total words suggested":"'.$this->suggestedWordCount.'","Spelling checked in":"'.$time.'" }; 00248 // --> 00249 /*]]>*/ 00250 </script> 00251 </head> 00252 '; 00253 $this->result .= '<body onload="window.parent.RTEarea[\'' . t3lib_div::_POST('editorId') . '\'].editor.getPlugin(\'SpellChecker\').spellCheckComplete();">'; 00254 $this->result .= preg_replace('/'.preg_quote('<?xml').'.*'.preg_quote('?>').'['.preg_quote(LF.CR.chr(32)).']*/'.(($this->parserCharset == 'utf-8')?'u':''), '', $this->text); 00255 $this->result .= '<div style="display: none;">'.$dictionaries.'</div>'; 00256 00257 // Closing 00258 $this->result .= ' 00259 </body></html>'; 00260 00261 // Outputting 00262 header('Content-Type: text/html; charset=' . strtoupper($this->parserCharset)); 00263 echo $this->result; 00264 } 00265 00266 } // end of function main 00267 00268 function startHandler($xml_parser, $tag, $attributes) { 00269 00270 if (strlen($this->xmlCharacterData)) { 00271 $this->spellCheckHandler($xml_parser, $this->xmlCharacterData); 00272 $this->xmlCharacterData = ''; 00273 } 00274 00275 switch($tag) { 00276 case 'spellchecker': 00277 break; 00278 case 'br': 00279 case 'BR': 00280 case 'img': 00281 case 'IMG': 00282 case 'hr': 00283 case 'HR': 00284 case 'area': 00285 case 'AREA': 00286 $this->text .= '<'. $this->csConvObj->conv_case($this->parserCharset, $tag, 'toLower') . ' '; 00287 foreach( $attributes as $key => $val) { 00288 $this->text .= $key . '="' . $val . '" '; 00289 } 00290 $this->text .= ' />'; 00291 break; 00292 default: 00293 $this->text .= '<'. $this->csConvObj->conv_case($this->parserCharset, $tag, 'toLower') . ' '; 00294 foreach( $attributes as $key => $val) { 00295 $this->text .= $key . '="' . $val . '" '; 00296 } 00297 $this->text .= '>'; 00298 break; 00299 } 00300 return; 00301 } 00302 00303 function endHandler($xml_parser, $tag) { 00304 if (strlen($this->xmlCharacterData)) { 00305 $this->spellCheckHandler($xml_parser, $this->xmlCharacterData); 00306 $this->xmlCharacterData = ''; 00307 } 00308 00309 switch($tag) { 00310 case 'spellchecker': 00311 break; 00312 case 'br': 00313 case 'BR': 00314 case 'img': 00315 case 'IMG': 00316 case 'hr': 00317 case 'HR': 00318 case 'input': 00319 case 'INPUT': 00320 case 'area': 00321 case 'AREA': 00322 break; 00323 default: 00324 $this->text .= '</' . $tag . '>'; 00325 break; 00326 } 00327 return; 00328 } 00329 00330 function spellCheckHandler($xml_parser, $string) { 00331 $incurrent=array(); 00332 $stringText = $string; 00333 $words = preg_split((($this->parserCharset == 'utf-8')?'/\P{L}+/u':'/\W+/'), $stringText); 00334 while( list(,$word) = each($words) ) { 00335 $word = preg_replace('/ /'.(($this->parserCharset == 'utf-8')?'u':''), '', $word); 00336 if( $word && !is_numeric($word)) { 00337 if($this->pspell_is_available && !$this->forceCommandMode) { 00338 if (!pspell_check($this->pspell_link, $word)) { 00339 if(!in_array($word, $this->misspelled)) { 00340 if(sizeof($this->misspelled) != 0 ) { 00341 $this->suggestedWords .= ','; 00342 } 00343 $suggest = array(); 00344 $suggest = pspell_suggest($this->pspell_link, $word); 00345 if(sizeof($suggest) != 0 ) { 00346 $this->suggestionCount++; 00347 $this->suggestedWordCount += sizeof($suggest); 00348 } 00349 $this->suggestedWords .= '"'.$word.'":"'.implode(',',$suggest).'"'; 00350 $this->misspelled[] = $word; 00351 unset($suggest); 00352 } 00353 if( !in_array($word, $incurrent) ) { 00354 $stringText = preg_replace('/\b'.$word.'\b/'.(($this->parserCharset == 'utf-8')?'u':''), '<span class="htmlarea-spellcheck-error">'.$word.'</span>', $stringText); 00355 $incurrent[] = $word; 00356 } 00357 } 00358 } else { 00359 $tmpFileName = t3lib_div::tempnam($this->filePrefix); 00360 if(!$filehandle = fopen($tmpFileName,'wb')) echo('SpellChecker tempfile open error'); 00361 if(!fwrite($filehandle, $word)) echo('SpellChecker tempfile write error'); 00362 if(!fclose($filehandle)) echo('SpellChecker tempfile close error'); 00363 $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'; 00364 $AspellAnswer = shell_exec($AspellCommand); 00365 $AspellResultLines = array(); 00366 $AspellResultLines = t3lib_div::trimExplode(LF, $AspellAnswer, 1); 00367 if(substr($AspellResultLines[0],0,6) == 'Error:') echo("{$AspellAnswer}"); 00368 t3lib_div::unlink_tempfile($tmpFileName); 00369 if(substr($AspellResultLines['1'],0,1) != '*') { 00370 if(!in_array($word, $this->misspelled)) { 00371 if(sizeof($this->misspelled) != 0 ) { 00372 $this->suggestedWords .= ','; 00373 } 00374 $suggest = array(); 00375 $suggestions = array(); 00376 if (substr($AspellResultLines['1'],0,1) == '&') { 00377 $suggestions = t3lib_div::trimExplode(':', $AspellResultLines['1'], 1); 00378 $suggest = t3lib_div::trimExplode(',', $suggestions['1'], 1); 00379 } 00380 if (sizeof($suggest) != 0) { 00381 $this->suggestionCount++; 00382 $this->suggestedWordCount += sizeof($suggest); 00383 } 00384 $this->suggestedWords .= '"'.$word.'":"'.implode(',',$suggest).'"'; 00385 $this->misspelled[] = $word; 00386 unset($suggest); 00387 unset($suggestions); 00388 } 00389 if (!in_array($word, $incurrent)) { 00390 $stringText = preg_replace('/\b'.$word.'\b/'.(($this->parserCharset == 'utf-8')?'u':''), '<span class="htmlarea-spellcheck-error">'.$word.'</span>', $stringText); 00391 $incurrent[] = $word; 00392 } 00393 } 00394 unset($AspellResultLines); 00395 } 00396 $this->wordCount++; 00397 } 00398 } 00399 $this->text .= $stringText; 00400 unset($incurrent); 00401 return; 00402 } 00403 00404 function collectDataHandler($xml_parser, $string) { 00405 $this->xmlCharacterData .= $string; 00406 } 00407 00408 function defaultHandler($xml_parser, $string) { 00409 $this->text .= $string; 00410 return; 00411 } 00412 00413 } 00414 00415 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/rtehtmlarea/pi1/class.tx_rtehtmlarea_pi1.php'])) { 00416 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/rtehtmlarea/pi1/class.tx_rtehtmlarea_pi1.php']); 00417 } 00418 00419 if (TYPO3_MODE=='FE') { 00420 tslib_eidtools::connectDB(); 00421 $spellChecker = t3lib_div::makeInstance('tx_rtehtmlarea_pi1'); 00422 $spellChecker->main(); 00423 } 00424 00425 ?>
1.8.0