155 $time_start = microtime(TRUE);
156 $this->pspell_is_available = in_array(
'pspell', get_loaded_extensions());
157 $this->AspellDirectory = trim(
$GLOBALS[
'TYPO3_CONF_VARS'][
'EXTCONF'][$this->extKey][
'plugins'][
'SpellChecker'][
'AspellDirectory']) ?:
'/usr/bin/aspell';
159 $this->forceCommandMode = trim(
$GLOBALS[
'TYPO3_CONF_VARS'][
'EXTCONF'][$this->extKey][
'plugins'][
'SpellChecker'][
'forceCommandMode']) ?: 0;
160 if (!$this->pspell_is_available || $this->forceCommandMode) {
161 $AspellVersionString = explode(
'Aspell', shell_exec($this->AspellDirectory .
' -v'));
162 $AspellVersion = substr($AspellVersionString[1], 0, 4);
163 if (doubleval($AspellVersion) < doubleval(
'0.5') && (!$this->pspell_is_available || $this->forceCommandMode)) {
164 echo
'Configuration problem: Aspell version ' . $AspellVersion .
' too old. Spell checking cannot be performed in command mode.';
166 $this->defaultAspellEncoding = trim(shell_exec($this->AspellDirectory .
' config encoding'));
169 $dictionaryList = shell_exec($this->AspellDirectory .
' dump dicts');
173 if ($restrictToDictionaries) {
176 if (!count($dictionaryArray)) {
177 $dictionaryArray[] =
'en';
181 if (!$defaultDictionary || !in_array($defaultDictionary, $dictionaryArray)) {
182 $defaultDictionary =
'en';
184 uasort($dictionaryArray,
'strcoll');
185 $dictionaryList = implode(
',', $dictionaryArray);
187 if (empty($this->dictionary) || !in_array($this->dictionary, $dictionaryArray)) {
188 $this->dictionary =
'en';
193 $this->pspellMode =
GeneralUtility::inList(
'ultra,fast,normal,bad-spellers', $this->pspellMode) ? $this->pspellMode :
'normal';
194 switch ($this->pspellMode) {
198 $pspellModeFlag = PSPELL_FAST;
201 $pspellModeFlag = PSPELL_BAD_SPELLERS;
206 $pspellModeFlag = PSPELL_NORMAL;
212 if (strtolower($this->charset) ==
'iso-8859-1') {
213 $this->parserCharset = strtolower($this->charset);
217 if ($this->parserCharset ==
'iso-8859-1' && strstr($this->defaultAspellEncoding,
'8859-1')) {
221 if ($this->pspell_is_available && !$this->forceCommandMode) {
222 $this->pspell_link = pspell_new($this->dictionary,
'',
'', $this->parserCharset, $pspellModeFlag);
230 if ($cmd ==
'learn') {
237 $to_p_dict = $to_p_dict ? $to_p_dict : array();
239 $to_r_list = $to_r_list ? $to_r_list : array();
240 header(
'Content-Type: text/plain; charset=' . strtoupper($this->parserCharset));
241 header(
'Pragma: no-cache');
242 if ($to_p_dict || $to_r_list) {
244 $filehandle = fopen($tmpFileName,
'wb');
250 foreach ($to_p_dict as $personal_word) {
251 $cmd =
'&' . $this->csConvObj->conv($personal_word, $this->parserCharset, $mainDictionaryCharacterSet) . LF;
252 fwrite($filehandle, $cmd, strlen($cmd));
255 foreach ($to_r_list as $replace_pair) {
256 $cmd =
'$$ra ' . $this->csConvObj->conv($replace_pair[0], $this->parserCharset, $mainDictionaryCharacterSet) .
' , ' . $this->csConvObj->conv($replace_pair[1], $this->parserCharset, $mainDictionaryCharacterSet) . LF;
257 fwrite($filehandle, $cmd, strlen($cmd));
260 $result = fwrite($filehandle, $cmd, strlen($cmd));
265 $aspellCommand = ((TYPO3_OS ===
'WIN') ?
'type ' :
'cat ') . escapeshellarg($tmpFileName) .
' | ' 266 . $this->AspellDirectory
268 . ($this->personalDictionaryPath ?
' --home-dir=' . escapeshellarg($this->personalDictionaryPath) :
'')
269 .
' --lang=' . escapeshellarg($this->dictionary)
270 .
' --encoding=' . escapeshellarg($mainDictionaryCharacterSet)
272 $aspellResult = shell_exec($aspellCommand);
286 $this->result =
'<?xml version="1.0" encoding="' . $this->parserCharset .
'"?> 288 PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 289 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 290 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="' . substr($this->dictionary, 0, 2) .
'" lang="' . substr($this->dictionary, 0, 2) .
'"> 292 <meta http-equiv="Content-Type" content="text/html; charset=' . $this->parserCharset .
'" /> 294 <script type="text/javascript"> 301 $parser = xml_parser_create(strtoupper($this->parserCharset));
303 $previousValueOfEntityLoader = libxml_disable_entity_loader(TRUE);
304 xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
305 xml_set_object($parser, $this);
306 if (!xml_set_element_handler($parser,
'startHandler',
'endHandler')) {
307 echo
'Bad xml handler setting';
309 if (!xml_set_character_data_handler($parser,
'collectDataHandler')) {
310 echo
'Bad xml handler setting';
312 if (!xml_set_default_handler($parser,
'defaultHandler')) {
313 echo
'Bad xml handler setting';
315 if (!xml_parse($parser, (
'<?xml version="1.0" encoding="' . $this->parserCharset .
'"?><spellchecker> ' . preg_replace((
'/ /' . ($this->parserCharset ==
'utf-8' ?
'u' :
'')),
' ', $content) .
' </spellchecker>'))) {
318 if (xml_get_error_code($parser)) {
319 throw new \UnexpectedException(
'Line ' . xml_get_current_line_number($parser) .
': ' . xml_error_string(xml_get_error_code($parser)), 1294585788);
321 libxml_disable_entity_loader($previousValueOfEntityLoader);
322 xml_parser_free($parser);
323 if ($this->pspell_is_available && !$this->forceCommandMode) {
324 pspell_clear_session($this->pspell_link);
326 $this->result .=
'var suggestedWords = {' . $this->suggestedWords .
'}; 327 var dictionaries = "' . $dictionaryList .
'"; 328 var selectedDictionary = "' . $this->dictionary .
'"; 331 $time = number_format(microtime(TRUE) - $time_start, 2,
',',
' ');
333 $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 .
'" }; 340 $this->result .= preg_replace(
'/' . preg_quote(
'<?xml') .
'.*' . preg_quote(
'?>') .
'[' . preg_quote((LF . CR . chr(32))) .
']*/' . ($this->parserCharset ==
'utf-8' ?
'u' :
''),
'', $this->text);
341 $this->result .=
'<div style="display: none;">' . $dictionaries .
'</div>';
346 header(
'Content-Type: text/html; charset=' . strtoupper($this->parserCharset));
357 $this->mainDictionaryPath =
'';
358 $aspellCommand = $this->AspellDirectory .
' config dict-dir';
359 $aspellResult = shell_exec($aspellCommand);
361 $this->mainDictionaryPath = trim($aspellResult);
363 if (!$aspellResult || !$this->mainDictionaryPath) {
376 if ($this->mainDictionaryPath) {
378 $mainDictionary = preg_split(
'/[-_]/', $this->dictionary, 2);
380 $dictionaryFileName = $this->mainDictionaryPath .
'/' . $mainDictionary[0] .
'.dat';
381 $dictionaryHandle = fopen($dictionaryFileName,
'rb');
382 if (!$dictionaryHandle) {
385 $dictionaryContent = fread($dictionaryHandle, 500);
386 if ($dictionaryContent === FALSE) {
389 fclose($dictionaryHandle);
391 $dictionaryContent = preg_split(
'/charset\s*/', $dictionaryContent, 2);
392 if ($dictionaryContent[1]) {
396 $characterSet = str_replace(
399 $dictionaryContent[0]
402 if (!$characterSet) {
408 return $characterSet;
417 $this->personalDictionaryPath =
'';
419 if (
$GLOBALS[
'BE_USER']->user[
'uid']) {
420 $personalDictionaryFolderName =
'BE_' .
$GLOBALS[
'BE_USER']->user[
'uid'];
425 $personalDictionaryFolder = FALSE;
428 if (!$personalDictionaryFolder) {
429 $personalDictionaryFolderName .=
'_personaldictionary';
430 $backendUserDefaultFolder =
$GLOBALS[
'BE_USER']->getDefaultUploadFolder();
431 if ($backendUserDefaultFolder->hasFolder($personalDictionaryFolderName)) {
432 $personalDictionaryFolder = $backendUserDefaultFolder->getSubfolder($personalDictionaryFolderName);
434 $personalDictionaryFolder = $backendUserDefaultFolder->createFolder($personalDictionaryFolderName);
437 $this->personalDictionaryPath = PATH_site . rtrim($personalDictionaryFolder->getPublicUrl(),
'/');
449 if ($this->personalDictionaryPath) {
452 $fileNames = array();
453 $mainDictionary = preg_split(
'/[-_]/', $this->dictionary, 2);
454 $fileNames[0] = $this->personalDictionaryPath .
'/' .
'.aspell.' . $mainDictionary[0] .
'.pws';
455 $fileNames[1] = $this->personalDictionaryPath .
'/' .
'.aspell.' . $mainDictionary[0] .
'.prepl';
456 foreach ($fileNames as $fileName) {
457 if (file_exists($fileName)) {
458 $fileContent = file_get_contents($fileName);
459 if ($fileContent === FALSE) {
462 $fileContent = explode(LF, $fileContent);
463 if (strpos($fileContent[0],
'utf-8') === FALSE) {
464 $fileContent[0] .=
' utf-8';
465 $fileContent = implode(LF, $fileContent);
466 $result = file_put_contents($fileName, $fileContent);
481 if (strlen($this->xmlCharacterData)) {
483 $this->xmlCharacterData =
'';
503 $this->text .=
'<' . $this->csConvObj->conv_case($this->parserCharset, $tag,
'toLower') .
' ';
504 foreach ($attributes as $key => $val) {
505 $this->text .= $key .
'="' . $val .
'" ';
507 $this->text .=
' />';
510 $this->text .=
'<' . $this->csConvObj->conv_case($this->parserCharset, $tag,
'toLower') .
' ';
511 foreach ($attributes as $key => $val) {
512 $this->text .= $key .
'="' . $val .
'" ';
522 if (strlen($this->xmlCharacterData)) {
524 $this->xmlCharacterData =
'';
550 $this->text .=
'</' . $tag .
'>';
558 $incurrent = array();
559 $stringText = $string;
560 $words = preg_split($this->parserCharset ==
'utf-8' ?
'/\\P{L}+/u' :
'/\\W+/', $stringText);
561 while (list(, $word) = each($words)) {
562 $word = preg_replace(
'/ /' . ($this->parserCharset ==
'utf-8' ?
'u' :
''),
'', $word);
563 if ($word && !is_numeric($word)) {
564 if ($this->pspell_is_available && !$this->forceCommandMode) {
565 if (!pspell_check($this->pspell_link, $word)) {
566 if (!in_array($word, $this->misspelled)) {
567 if (
sizeof($this->misspelled) != 0) {
568 $this->suggestedWords .=
',';
571 $suggest = pspell_suggest($this->pspell_link, $word);
572 if (
sizeof($suggest) != 0) {
573 $this->suggestionCount++;
574 $this->suggestedWordCount +=
sizeof($suggest);
576 $this->suggestedWords .=
'"' . $word .
'":"' . implode(
',', $suggest) .
'"';
577 $this->misspelled[] = $word;
580 if (!in_array($word, $incurrent)) {
581 $stringText = preg_replace(
'/\\b' . $word .
'\\b/' . ($this->parserCharset ==
'utf-8' ?
'u' :
''),
'<span class="htmlarea-spellcheck-error">' . $word .
'</span>', $stringText);
582 $incurrent[] = $word;
587 if (!($filehandle = fopen($tmpFileName,
'wb'))) {
588 echo
'SpellChecker tempfile open error';
590 if (!fwrite($filehandle, $word)) {
591 echo
'SpellChecker tempfile write error';
593 if (!fclose($filehandle)) {
594 echo
'SpellChecker tempfile close error';
596 $catCommand = TYPO3_OS ==
'WIN' ?
'type' :
'cat';
597 $AspellCommand = $catCommand .
' ' . escapeshellarg($tmpFileName) .
' | ' . $this->AspellDirectory .
' -a check --mode=none --sug-mode=' . escapeshellarg($this->pspellMode) . ($this->personalDictionaryPath ?
' --home-dir=' . escapeshellarg($this->personalDictionaryPath) :
'') .
' --lang=' . escapeshellarg($this->dictionary) .
' --encoding=' . escapeshellarg($this->aspellEncoding) .
' 2>&1';
598 $AspellAnswer = shell_exec($AspellCommand);
599 $AspellResultLines = array();
601 if (substr($AspellResultLines[0], 0, 6) ==
'Error:') {
602 echo
'{' . $AspellAnswer .
'}';
605 if ($AspellResultLines[
'1'][0] !==
'*') {
606 if (!in_array($word, $this->misspelled)) {
607 if (
sizeof($this->misspelled) != 0) {
608 $this->suggestedWords .=
',';
611 $suggestions = array();
612 if ($AspellResultLines[
'1'][0] ===
'&') {
616 if (
sizeof($suggest) != 0) {
617 $this->suggestionCount++;
618 $this->suggestedWordCount +=
sizeof($suggest);
620 $this->suggestedWords .=
'"' . $word .
'":"' . implode(
',', $suggest) .
'"';
621 $this->misspelled[] = $word;
625 if (!in_array($word, $incurrent)) {
626 $stringText = preg_replace(
'/\\b' . $word .
'\\b/' . ($this->parserCharset ==
'utf-8' ?
'u' :
''),
'<span class="htmlarea-spellcheck-error">' . $word .
'</span>', $stringText);
627 $incurrent[] = $word;
630 unset($AspellResultLines);
635 $this->text .= $stringText;
643 $this->xmlCharacterData .= $string;
650 $this->text .= $string;
defaultHandler($xml_parser, $string)
static unlink_tempfile($uploadedTempFileName)
fixPersonalDictionaryCharacterSet()
static quoteJSvalue($value)
static makeInstance($className)
startHandler($xml_parser, $tag, $attributes)
static trimExplode($delim, $string, $removeEmptyValues=FALSE, $limit=0)
const SYSLOG_SEVERITY_ERROR
collectDataHandler($xml_parser, $string)
spellCheckHandler($xml_parser, $string)
setPersonalDictionaryPath()
endHandler($xml_parser, $tag)
static tempnam($filePrefix, $fileSuffix='')
getMainDictionaryCharacterSet()
if(!defined('TYPO3_MODE')) $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauth.php']['logoff_pre_processing'][]
static inList($list, $item)