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