TYPO3CMS  8
 All Classes Namespaces Files Functions Variables Pages
SpellCheckingController.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Rtehtmlarea\Controller;
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
17 use Psr\Http\Message\ResponseInterface;
18 use Psr\Http\Message\ServerRequestInterface;
20 
25 {
29  protected $csConvObj;
30 
31  // The extension key
35  public $extKey = 'rtehtmlarea';
36 
40  public $siteUrl;
41 
45  public $charset = 'utf-8';
46 
50  public $parserCharset = 'utf-8';
51 
55  public $defaultAspellEncoding = 'utf-8';
56 
61 
65  public $result;
66 
70  public $text;
71 
75  public $misspelled = [];
76 
81 
85  public $wordCount = 0;
86 
90  public $suggestionCount = 0;
91 
95  public $suggestedWordCount = 0;
96 
100  public $pspell_link;
101 
105  public $pspellMode = 'normal';
106 
110  public $dictionary;
111 
116 
121 
125  public $forceCommandMode = 0;
126 
130  public $filePrefix = 'rtehtmlarea_';
131 
132  // Pre-FAL backward compatibility
133  protected $uploadFolder = 'uploads/tx_rtehtmlarea/';
134 
135  // Path to main dictionary
137 
138  // Path to personal dictionary
140 
144  public $xmlCharacterData = '';
145 
155  public function main(ServerRequestInterface $request, ResponseInterface $response)
156  {
158  return $this->processRequest($request, $response);
159  }
160 
170  public function processRequest(ServerRequestInterface $request, ResponseInterface $response)
171  {
172  $this->csConvObj = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Charset\CharsetConverter::class);
173  // Setting start time
174  $time_start = microtime(true);
175  $this->pspell_is_available = in_array('pspell', get_loaded_extensions());
176  $this->AspellDirectory = trim($GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][$this->extKey]['plugins']['SpellChecker']['AspellDirectory']) ?: '/usr/bin/aspell';
177  // Setting command mode if requested and available
178  $this->forceCommandMode = trim($GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][$this->extKey]['plugins']['SpellChecker']['forceCommandMode']) ?: 0;
179  if (!$this->pspell_is_available || $this->forceCommandMode) {
180  $AspellVersionString = explode('Aspell', shell_exec($this->AspellDirectory . ' -v'));
181  $AspellVersion = substr($AspellVersionString[1], 0, 4);
182  if ((float)$AspellVersion < 0.5 && (!$this->pspell_is_available || $this->forceCommandMode)) {
183  echo 'Configuration problem: Aspell version ' . $AspellVersion . ' too old. Spell checking cannot be performed in command mode.';
184  }
185  $this->defaultAspellEncoding = trim(shell_exec($this->AspellDirectory . ' config encoding'));
186  }
187  // Setting the list of dictionaries
188  $dictionaryList = shell_exec($this->AspellDirectory . ' dump dicts');
189  $dictionaryList = implode(',', GeneralUtility::trimExplode(LF, $dictionaryList, true));
190  $dictionaryArray = GeneralUtility::trimExplode(',', $dictionaryList, true);
191  $restrictToDictionaries = GeneralUtility::_POST('restrictToDictionaries');
192  if ($restrictToDictionaries) {
193  $dictionaryArray = array_intersect($dictionaryArray, GeneralUtility::trimExplode(',', $restrictToDictionaries, 1));
194  }
195  if (empty($dictionaryArray)) {
196  $dictionaryArray[] = 'en';
197  }
198  $this->dictionary = GeneralUtility::_POST('dictionary');
199  uasort($dictionaryArray, 'strcoll');
200  $dictionaryList = implode(',', $dictionaryArray);
201  // Setting the dictionary
202  if (empty($this->dictionary) || !in_array($this->dictionary, $dictionaryArray)) {
203  $this->dictionary = 'en';
204  }
205  // Setting the pspell suggestion mode
206  $this->pspellMode = GeneralUtility::_POST('pspell_mode') ? GeneralUtility::_POST('pspell_mode') : $this->pspellMode;
207  switch ($this->pspellMode) {
208  case 'ultra':
209 
210  case 'fast':
211  $pspellModeFlag = PSPELL_FAST;
212  break;
213  case 'bad-spellers':
214  $pspellModeFlag = PSPELL_BAD_SPELLERS;
215  break;
216  case 'normal':
217 
218  default:
219  $pspellModeFlag = PSPELL_NORMAL;
220  // sanitize $this->pspellMode
221  $this->pspellMode = 'normal';
222  }
223  // Setting the charset
224  if (GeneralUtility::_POST('pspell_charset')) {
225  $this->charset = trim(GeneralUtility::_POST('pspell_charset'));
226  }
227  if (strtolower($this->charset) == 'iso-8859-1') {
228  $this->parserCharset = strtolower($this->charset);
229  }
230  // In some configurations, Aspell uses 'iso8859-1' instead of 'iso-8859-1'
231  $this->aspellEncoding = $this->parserCharset;
232  if ($this->parserCharset == 'iso-8859-1' && strstr($this->defaultAspellEncoding, '8859-1')) {
233  $this->aspellEncoding = $this->defaultAspellEncoding;
234  }
235  // However, we are going to work only in the parser charset
236  if ($this->pspell_is_available && !$this->forceCommandMode) {
237  $this->pspell_link = pspell_new($this->dictionary, '', '', $this->parserCharset, $pspellModeFlag);
238  }
239  // Setting the path to main dictionary
240  $this->setMainDictionaryPath();
241  // Setting the path to user personal dictionary, if any
242  $this->setPersonalDictionaryPath();
244  $cmd = GeneralUtility::_POST('cmd');
245  if ($cmd == 'learn') {
246  // Only availble for BE_USERS, die silently if someone has gotten here by accident
247  if (TYPO3_MODE !== 'BE' || !is_object($GLOBALS['BE_USER'])) {
248  die('');
249  }
250  // Updating the personal word list
251  $to_p_dict = GeneralUtility::_POST('to_p_dict');
252  $to_p_dict = $to_p_dict ? $to_p_dict : [];
253  $to_r_list = GeneralUtility::_POST('to_r_list');
254  $to_r_list = $to_r_list ? $to_r_list : [];
255  header('Content-Type: text/plain; charset=' . strtoupper($this->parserCharset));
256  header('Pragma: no-cache');
257  if ($to_p_dict || $to_r_list) {
258  $tmpFileName = GeneralUtility::tempnam($this->filePrefix);
259  $filehandle = fopen($tmpFileName, 'wb');
260  if ($filehandle) {
261  // Get the character set of the main dictionary
262  // We need to convert the input into the character set of the main dictionary
263  $mainDictionaryCharacterSet = $this->getMainDictionaryCharacterSet();
264  // Write the personal words addition commands to the temporary file
265  foreach ($to_p_dict as $personal_word) {
266  $cmd = '&' . $this->csConvObj->conv($personal_word, $this->parserCharset, $mainDictionaryCharacterSet) . LF;
267  fwrite($filehandle, $cmd, strlen($cmd));
268  }
269  // Write the replacent pairs addition commands to the temporary file
270  foreach ($to_r_list as $replace_pair) {
271  $cmd = '$$ra ' . $this->csConvObj->conv($replace_pair[0], $this->parserCharset, $mainDictionaryCharacterSet) . ' , ' . $this->csConvObj->conv($replace_pair[1], $this->parserCharset, $mainDictionaryCharacterSet) . LF;
272  fwrite($filehandle, $cmd, strlen($cmd));
273  }
274  $cmd = '#' . LF;
275  $result = fwrite($filehandle, $cmd, strlen($cmd));
276  if ($result === false) {
277  GeneralUtility::sysLog('SpellChecker tempfile write error: ' . $tmpFileName, $this->extKey, GeneralUtility::SYSLOG_SEVERITY_ERROR);
278  } else {
279  // Assemble the Aspell command
280  $aspellCommand = ((TYPO3_OS === 'WIN') ? 'type ' : 'cat ') . escapeshellarg($tmpFileName) . ' | '
281  . $this->AspellDirectory
282  . ' -a --mode=none'
283  . ($this->personalDictionaryPath ? ' --home-dir=' . escapeshellarg($this->personalDictionaryPath) : '')
284  . ' --lang=' . escapeshellarg($this->dictionary)
285  . ' --encoding=' . escapeshellarg($mainDictionaryCharacterSet)
286  . ' 2>&1';
287  $aspellResult = shell_exec($aspellCommand);
288  // Close and delete the temporary file
289  fclose($filehandle);
290  GeneralUtility::unlink_tempfile($tmpFileName);
291  }
292  } else {
293  GeneralUtility::sysLog('SpellChecker tempfile open error: ' . $tmpFileName, $this->extKey, GeneralUtility::SYSLOG_SEVERITY_ERROR);
294  }
295  }
296  flush();
297  die;
298  } else {
299  // Check spelling content
300  // Initialize output
301  $this->result = '<?xml version="1.0" encoding="' . $this->parserCharset . '"?>
302 <!DOCTYPE html
303  PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
304  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
305 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="' . substr($this->dictionary, 0, 2) . '" lang="' . substr($this->dictionary, 0, 2) . '">
306 <head>
307 <meta http-equiv="Content-Type" content="text/html; charset=' . $this->parserCharset . '" />
308 <link rel="stylesheet" type="text/css" media="all" href="' . (TYPO3_MODE == 'BE' ? '../' : '') . \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::siteRelPath($this->extKey) . '/Resources/Public/Css/Skin/Plugins/spell-checker-iframe.css" />
309 <script type="text/javascript">
310 /*<![CDATA[*/
311 <!--
312 ';
313  // Getting the input content
314  $content = GeneralUtility::_POST('content');
315  // Parsing the input HTML
316  $parser = xml_parser_create(strtoupper($this->parserCharset));
317  // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept
318  $previousValueOfEntityLoader = libxml_disable_entity_loader(true);
319  xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
320  xml_set_object($parser, $this);
321  if (!xml_set_element_handler($parser, 'startHandler', 'endHandler')) {
322  echo 'Bad xml handler setting';
323  }
324  if (!xml_set_character_data_handler($parser, 'collectDataHandler')) {
325  echo 'Bad xml handler setting';
326  }
327  if (!xml_set_default_handler($parser, 'defaultHandler')) {
328  echo 'Bad xml handler setting';
329  }
330  if (!xml_parse($parser, ('<?xml version="1.0" encoding="' . $this->parserCharset . '"?><spellchecker> ' . preg_replace(('/&nbsp;/' . ($this->parserCharset == 'utf-8' ? 'u' : '')), ' ', $content) . ' </spellchecker>'))) {
331  echo 'Bad parsing';
332  }
333  if (xml_get_error_code($parser)) {
334  throw new \UnexpectedValueException('Line ' . xml_get_current_line_number($parser) . ': ' . xml_error_string(xml_get_error_code($parser)), 1294585788);
335  }
336  libxml_disable_entity_loader($previousValueOfEntityLoader);
337  xml_parser_free($parser);
338  if ($this->pspell_is_available && !$this->forceCommandMode) {
339  pspell_clear_session($this->pspell_link);
340  }
341  $this->result .= 'var suggestedWords = {' . $this->suggestedWords . '};
342 var dictionaries = "' . $dictionaryList . '";
343 var selectedDictionary = "' . $this->dictionary . '";
344 ';
345  // Calculating parsing and spell checkting time
346  $time = number_format(microtime(true) - $time_start, 2, ',', ' ');
347  // Insert spellcheck info
348  $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 . '" };
349 // -->
350 /*]]>*/
351 </script>
352 </head>
353 ';
354  $this->result .= '<body onload="window.parent.RTEarea[' . GeneralUtility::quoteJSvalue(GeneralUtility::_POST('editorId')) . '].editor.getPlugin(\'SpellChecker\').spellCheckComplete();">';
355  $this->result .= preg_replace('/' . preg_quote('<?xml') . '.*' . preg_quote('?>') . '[' . preg_quote((LF . CR . chr(32))) . ']*/' . ($this->parserCharset == 'utf-8' ? 'u' : ''), '', $this->text);
356  // Closing
357  $this->result .= '
358 </body></html>';
359  // Outputting
360  $response = $response->withHeader('Content-Type', 'text/html; charset=' . strtoupper($this->parserCharset));
361  $response->getBody()->write($this->result);
362  return $response;
363  }
364  }
365 
371  protected function setMainDictionaryPath()
372  {
373  $this->mainDictionaryPath = '';
374  $aspellCommand = $this->AspellDirectory . ' config dict-dir';
375  $aspellResult = shell_exec($aspellCommand);
376  if ($aspellResult) {
377  $this->mainDictionaryPath = trim($aspellResult);
378  }
379  if (!$aspellResult || !$this->mainDictionaryPath) {
380  GeneralUtility::sysLog('SpellChecker main dictionary path retrieval error: ' . $aspellCommand, $this->extKey, GeneralUtility::SYSLOG_SEVERITY_ERROR);
381  }
383  }
384 
390  protected function getMainDictionaryCharacterSet()
391  {
392  $characterSet = '';
393  if ($this->mainDictionaryPath) {
394  // Keep only the first part of the dictionary name
395  $mainDictionary = preg_split('/[-_]/', $this->dictionary, 2);
396  // Read the options of the dictionary
397  $dictionaryFileName = $this->mainDictionaryPath . '/' . $mainDictionary[0] . '.dat';
398  $dictionaryHandle = fopen($dictionaryFileName, 'rb');
399  if (!$dictionaryHandle) {
400  GeneralUtility::sysLog('SpellChecker main dictionary open error: ' . $dictionaryFileName, $this->extKey, GeneralUtility::SYSLOG_SEVERITY_ERROR);
401  } else {
402  $dictionaryContent = fread($dictionaryHandle, 500);
403  if ($dictionaryContent === false) {
404  GeneralUtility::sysLog('SpellChecker main dictionary read error: ' . $dictionaryFileName, $this->extKey, GeneralUtility::SYSLOG_SEVERITY_ERROR);
405  } else {
406  fclose($dictionaryHandle);
407  // Get the line that contains the character set option
408  $dictionaryContent = preg_split('/charset\s*/', $dictionaryContent, 2);
409  if ($dictionaryContent[1]) {
410  // Isolate the character set
411  $dictionaryContent = GeneralUtility::trimExplode(LF, $dictionaryContent[1]);
412  // Fix Aspell character set oddity (i.e. iso8859-1)
413  $characterSet = str_replace(
414  ['iso', '--'],
415  ['iso-', '-'],
416  $dictionaryContent[0]
417  );
418  }
419  if (!$characterSet) {
420  GeneralUtility::sysLog('SpellChecker main dictionary character set retrieval error: ' . $dictionaryContent[1], $this->extKey, GeneralUtility::SYSLOG_SEVERITY_ERROR);
421  }
422  }
423  }
424  }
425  return $characterSet;
426  }
427 
433  protected function setPersonalDictionaryPath()
434  {
435  $this->personalDictionaryPath = '';
436  if (GeneralUtility::_POST('enablePersonalDicts') == 'true' && TYPO3_MODE == 'BE' && is_object($GLOBALS['BE_USER'])) {
437  if ($GLOBALS['BE_USER']->user['uid']) {
438  $personalDictionaryFolderName = 'BE_' . $GLOBALS['BE_USER']->user['uid'];
439  // Check for pre-FAL personal dictionary folder
440  try {
441  $personalDictionaryFolder = \TYPO3\CMS\Core\Resource\ResourceFactory::getInstance()->getFolderObjectFromCombinedIdentifier(PATH_site . $this->uploadFolder . $personalDictionaryFolderName);
442  } catch (\Exception $e) {
443  $personalDictionaryFolder = false;
444  }
445  // The personal dictionary folder is created in the user's default upload folder and named BE_(uid)_personaldictionary
446  if (!$personalDictionaryFolder) {
447  $personalDictionaryFolderName .= '_personaldictionary';
448  $backendUserDefaultFolder = $GLOBALS['BE_USER']->getDefaultUploadFolder();
449  if ($backendUserDefaultFolder->hasFolder($personalDictionaryFolderName)) {
450  $personalDictionaryFolder = $backendUserDefaultFolder->getSubfolder($personalDictionaryFolderName);
451  } else {
452  $personalDictionaryFolder = $backendUserDefaultFolder->createFolder($personalDictionaryFolderName);
453  }
454  }
455  $this->personalDictionaryPath = PATH_site . rtrim($personalDictionaryFolder->getPublicUrl(), '/');
456  }
457  }
459  }
460 
467  {
468  if ($this->personalDictionaryPath) {
469  // Fix the options of the personl word list and of the replacement pairs files
470  // Aspell creates such files only for the main dictionary
471  $fileNames = [];
472  $mainDictionary = preg_split('/[-_]/', $this->dictionary, 2);
473  $fileNames[0] = $this->personalDictionaryPath . '/' . '.aspell.' . $mainDictionary[0] . '.pws';
474  $fileNames[1] = $this->personalDictionaryPath . '/' . '.aspell.' . $mainDictionary[0] . '.prepl';
475  foreach ($fileNames as $fileName) {
476  if (file_exists($fileName)) {
477  $fileContent = file_get_contents($fileName);
478  if ($fileContent === false) {
479  GeneralUtility::sysLog('SpellChecker personal word list read error: ' . $fileName, $this->extKey, GeneralUtility::SYSLOG_SEVERITY_ERROR);
480  } else {
481  $fileContent = explode(LF, $fileContent);
482  if (strpos($fileContent[0], 'utf-8') === false) {
483  $fileContent[0] .= ' utf-8';
484  $fileContent = implode(LF, $fileContent);
485  $result = file_put_contents($fileName, $fileContent);
486  if ($result === false) {
487  GeneralUtility::sysLog('SpellChecker personal word list write error: ' . $fileName, $this->extKey, GeneralUtility::SYSLOG_SEVERITY_ERROR);
488  }
489  }
490  }
491  }
492  }
493  }
494  }
495 
499  public function startHandler($xml_parser, $tag, $attributes)
500  {
501  if ((string)$this->xmlCharacterData !== '') {
502  $this->spellCheckHandler($xml_parser, $this->xmlCharacterData);
503  $this->xmlCharacterData = '';
504  }
505  switch ($tag) {
506  case 'spellchecker':
507  break;
508  case 'br':
509 
510  case 'BR':
511 
512  case 'img':
513 
514  case 'IMG':
515 
516  case 'hr':
517 
518  case 'HR':
519 
520  case 'area':
521 
522  case 'AREA':
523  $this->text .= '<' . mb_strtolower($tag, $this->parserCharset) . ' ';
524  foreach ($attributes as $key => $val) {
525  $this->text .= $key . '="' . $val . '" ';
526  }
527  $this->text .= ' />';
528  break;
529  default:
530  $this->text .= '<' . mb_strtolower($tag, $this->parserCharset) . ' ';
531  foreach ($attributes as $key => $val) {
532  $this->text .= $key . '="' . $val . '" ';
533  }
534  $this->text .= '>';
535  }
536  }
537 
541  public function endHandler($xml_parser, $tag)
542  {
543  if ((string)$this->xmlCharacterData !== '') {
544  $this->spellCheckHandler($xml_parser, $this->xmlCharacterData);
545  $this->xmlCharacterData = '';
546  }
547  switch ($tag) {
548  case 'spellchecker':
549 
550  case 'br':
551 
552  case 'BR':
553 
554  case 'img':
555 
556  case 'IMG':
557 
558  case 'hr':
559 
560  case 'HR':
561 
562  case 'input':
563 
564  case 'INPUT':
565 
566  case 'area':
567 
568  case 'AREA':
569  break;
570  default:
571  $this->text .= '</' . $tag . '>';
572  }
573  }
574 
578  public function spellCheckHandler($xml_parser, $string)
579  {
580  $incurrent = [];
581  $stringText = $string;
582  $words = preg_split($this->parserCharset == 'utf-8' ? '/\\P{L}+/u' : '/\\W+/', $stringText);
583  foreach ($words as $word) {
584  $word = preg_replace('/ /' . ($this->parserCharset == 'utf-8' ? 'u' : ''), '', $word);
585  if ($word && !is_numeric($word)) {
586  if ($this->pspell_is_available && !$this->forceCommandMode) {
587  if (!pspell_check($this->pspell_link, $word)) {
588  if (!in_array($word, $this->misspelled)) {
589  if (sizeof($this->misspelled) != 0) {
590  $this->suggestedWords .= ',';
591  }
592  $suggest = pspell_suggest($this->pspell_link, $word);
593  if (sizeof($suggest) != 0) {
594  $this->suggestionCount++;
595  $this->suggestedWordCount += sizeof($suggest);
596  }
597  $this->suggestedWords .= '"' . $word . '":"' . implode(',', $suggest) . '"';
598  $this->misspelled[] = $word;
599  unset($suggest);
600  }
601  if (!in_array($word, $incurrent)) {
602  $stringText = preg_replace('/\\b' . $word . '\\b/' . ($this->parserCharset == 'utf-8' ? 'u' : ''), '<span class="htmlarea-spellcheck-error">' . $word . '</span>', $stringText);
603  $incurrent[] = $word;
604  }
605  }
606  } else {
607  $tmpFileName = GeneralUtility::tempnam($this->filePrefix);
608  if (!($filehandle = fopen($tmpFileName, 'wb'))) {
609  echo 'SpellChecker tempfile open error';
610  }
611  if (!fwrite($filehandle, $word)) {
612  echo 'SpellChecker tempfile write error';
613  }
614  if (!fclose($filehandle)) {
615  echo 'SpellChecker tempfile close error';
616  }
617  $catCommand = TYPO3_OS === 'WIN' ? 'type' : 'cat';
618  $AspellCommand = $catCommand . ' ' . escapeshellarg($tmpFileName) . ' | '
619  . $this->AspellDirectory
620  . ' -a check'
621  . ' --mode=none'
622  . ' --sug-mode=' . escapeshellarg($this->pspellMode)
623  . ($this->personalDictionaryPath ? ' --home-dir=' . escapeshellarg($this->personalDictionaryPath) : '')
624  . ' --lang=' . escapeshellarg($this->dictionary)
625  . ' --encoding=' . escapeshellarg($this->aspellEncoding)
626  . ' 2>&1';
627  $AspellAnswer = shell_exec($AspellCommand);
628  $AspellResultLines = GeneralUtility::trimExplode(LF, $AspellAnswer, true);
629  if (substr($AspellResultLines[0], 0, 6) == 'Error:') {
630  echo '{' . $AspellAnswer . '}';
631  }
632  GeneralUtility::unlink_tempfile($tmpFileName);
633  if ($AspellResultLines['1'][0] !== '*') {
634  if (!in_array($word, $this->misspelled)) {
635  if (sizeof($this->misspelled) != 0) {
636  $this->suggestedWords .= ',';
637  }
638  $suggest = [];
639  $suggestions = [];
640  if ($AspellResultLines['1'][0] === '&') {
641  $suggestions = GeneralUtility::trimExplode(':', $AspellResultLines['1'], true);
642  $suggest = GeneralUtility::trimExplode(',', $suggestions['1'], true);
643  }
644  if (sizeof($suggest) != 0) {
645  $this->suggestionCount++;
646  $this->suggestedWordCount += sizeof($suggest);
647  }
648  $this->suggestedWords .= '"' . $word . '":"' . implode(',', $suggest) . '"';
649  $this->misspelled[] = $word;
650  unset($suggest);
651  unset($suggestions);
652  }
653  if (!in_array($word, $incurrent)) {
654  $stringText = preg_replace('/\\b' . $word . '\\b/' . ($this->parserCharset == 'utf-8' ? 'u' : ''), '<span class="htmlarea-spellcheck-error">' . $word . '</span>', $stringText);
655  $incurrent[] = $word;
656  }
657  }
658  unset($AspellResultLines);
659  }
660  $this->wordCount++;
661  }
662  }
663  $this->text .= $stringText;
664  unset($incurrent);
665  }
666 
670  public function collectDataHandler($xml_parser, $string)
671  {
672  $this->xmlCharacterData .= $string;
673  }
674 
678  public function defaultHandler($xml_parser, $string)
679  {
680  $this->text .= $string;
681  }
682 }
static trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
main(ServerRequestInterface $request, ResponseInterface $response)
static unlink_tempfile($uploadedTempFileName)
static tempnam($filePrefix, $fileSuffix= '')
if(TYPO3_MODE=== 'BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
processRequest(ServerRequestInterface $request, ResponseInterface $response)
static makeInstance($className,...$constructorArguments)