Extracts the markup wrapped with TYPO3SEARCH_begin and TYPO3SEARCH_end
markers.

@param string $html HTML markup with TYPO3SEARCH markers for content that should be indexed
@return string HTML markup found between TYPO3SEARCH markers
340743
protected function extractContentMarkedForIndexing($html)
    {
        preg_match_all('/<!--\s*?TYPO3SEARCH_begin\s*?-->.*?<!--\s*?TYPO3SEARCH_end\s*?-->/mis',
            $html, $indexableContents);
        $indexableContent = implode($indexableContents[0], '');

        $indexableContent = $this->excludeContentByClass($indexableContent);
        if (empty($indexableContent) && $this->getConfiguration()->getLoggingIndexingMissingTypo3SearchMarkers()) {
            $this->logger = GeneralUtility::makeInstance(SolrLogManager::class, /** @scrutinizer ignore-type */ __CLASS__);
            $this->logger->log(SolrLogManager::WARNING, 'No TYPO3SEARCH markers found.');
        }

        return $indexableContent;
    }
52986
protected function getErrorLevelForAdditionalHtml($html)
	{
		if (preg_match('#^<(i|b|ul|ol|li|h3)( style="[a-zA-Z0-9_\:\ \;\-]+")?>$#', $html))
		{
			return Output::ERROR;
		}

		if (in_array($html, array(
			'<em>',
			'<strong>',
			'<samp>',
			'<u>',
			'<br />',
			'<br>',
			'<hr>'
		)))
		{
			return Output::NOTICE;
		}

		if (preg_match('#^<a href="([a-zA-Z0-9_\:\&\/\?\.\-\#\@]+)">$#', $html) ||
			preg_match('#^<a href="([a-zA-Z0-9_\:\&\/\?\.\-\#]+)" rel="external">$#', $html))
		{
			return Output::ERROR;
		}

		return Output::FATAL;
	}
124227
public function format($html = false) {
        $format  = '%s: %s';

        if ($this->lastLine > 0) {
            $format .= PHP_EOL;
            $format .= 'From line %d, column %d; ' ;
            $format .= 'to line %d, column %d';
        }

        $message = sprintf(
            $format,
            $html ? '<strong>' . $this->type . '</strong>' : $this->type,
            $html ? htmlentities($this->text, ENT_COMPAT, 'UTF-8') : $this->text,
            $this->firstLine,
            $this->firstColumn,
            $this->lastLine,
            $this->lastColumn
        );

        if (!$html) {
            return $message . PHP_EOL . $this->extract;
        }

        // Check if the user has specified a custom highlighter
        if ($this->highlighter) {
            $highlighter = $this->highlighter;
            $extract = $highlighter($this->extract, $this->hiliteStart, $this->hiliteLength);
        } else {
            $extract = $this->highlight($this->extract, $this->hiliteStart, $this->hiliteLength);
        }

        $message .= PHP_EOL . $extract;
        return nl2br($message, false);
    }
440568
public function extractExternalJavaScript($html)
    {
        $matches = array();

        preg_match_all(
            '!' . $this->getExternalJavaScriptRegex() . '!isU',
            $html, $matches
        );

        $links = $this->createJavaScriptPaths($matches['links']);

        return array('tags' => $matches[0], 'links' => $links);
    }
369801
public function parse(string $html): string
    {
        $html = ltrim($html);
        $this->setTokenPosition($html);

        try {
            $this->name = $this->parseElementName($html);
            $remainingHtml = $this->parseAttributes($html);
            $posOfClosingBracket = $this->getPositionOfElementEndTag($remainingHtml);

            // Is self-closing?
            $posOfSelfClosingBracket = \mb_strpos($remainingHtml, '/>');
            $remainingHtml = \mb_substr($remainingHtml, $posOfClosingBracket + 1);
            if ($posOfSelfClosingBracket !== false && $posOfSelfClosingBracket === $posOfClosingBracket - 1) {
                // Self-closing element. (Note: $this->valuue is unchanged.)
                return $remainingHtml;
            }

            // Lets close those closed-only elements that are left open.
            if (\in_array($this->name, self::VOID_ELEMENTS, true)) {
                return $remainingHtml;
            }

            // Open element.
            return $this->parseContents($remainingHtml);
        } catch (ParseException $e) {
            if ($this->getThrowOnError()) {
                throw $e;
            }
        }

        return '';
    }
937271
private function ensureDocumentType($html)
    {
        $hasDocumentType = \stripos($html, '<!DOCTYPE') !== false;
        if ($hasDocumentType) {
            return $html;
        }

        return static::DEFAULT_DOCUMENT_TYPE . $html;
    }
98513
protected static function getEndPointFromDom(\DOMDocument $html)
    {
        foreach (['link', 'meta'] as $tagName) {
            foreach (Utils::getLinks($html, $tagName) as $link) {
                list($rel, $href, $element) = $link;

                if (empty($href)) {
                    continue;
                }

                if ($rel === 'alternate') {
                    switch (strtolower($element->getAttribute('type'))) {
                        case 'application/json+oembed':
                        case 'application/xml+oembed':
                        case 'text/json+oembed':
                        case 'text/xml+oembed':
                            return $href;
                    }
                }
            }
        }
    }
1276286
public function loadHTML($html)
    {
        $html = str_replace(chr(13), '', $html);
        $html = '<?xml version="1.0" encoding="utf-8" ?><' . $this->PARENT_TAG_NAME . '>' . $html . '</' . $this->PARENT_TAG_NAME . '>';
        if (defined('LIBXML_HTML_NODEFDTD')) {
            return $this->dom->loadHTML($html, LIBXML_HTML_NODEFDTD);
        } else {
            return $this->dom->loadHTML($html);
        }


    }
107596
protected function removeEmptyTags($html)
    {
        if (!\is_string($html)) {
            return $html;
        }
        /*
            Toss empty tags such as label or legend
            keep empty textarea
        */
        $html = \preg_replace('#^\s*<(div|label|legend|span)\b[^>]*>\s*</\1>\n#m', '', $html);
        $html = \preg_replace('#^\s*\n#m', '', $html);  // toss empty lines
        $html = \preg_replace('#<(\w+) >#', '<$1>', $html);   // <tab > ->  <tab>
        return $html;
    }
116761
public function parseString($html)
    {
        /** TODO: custom markdown-extra options, e.g. titles & classes **/
        // <sup id="fnref:..."><a href"#fn..." rel="footnote">...</a></sup>
        // => <fnref target="..." />
        $html = preg_replace('@<sup id="fnref:([^"]+)">\s*<a href="#fn:\1" rel="footnote">\s*\d+\s*</a>\s*</sup>@Us', '<fnref target="$1" />', $html);
        // <div class="footnotes">
        // <hr />
        // <ol>
        //
        // <li id="fn:...">...</li>
        // ...
        //
        // </ol>
        // </div>
        // =>
        // <footnotes>
        //   <fn name="...">...</fn>
        //   ...
        // </footnotes>
        $html = preg_replace_callback('#<div class="footnotes">\s*<hr />\s*<ol>\s*(.+)\s*</ol>\s*</div>#Us', [&$this, '_makeFootnotes'], $html);

        return parent::parseString($html);
    }
592561
private function parseNoContents(string $tag, string $html): string
    {
        $remainingHtml = \ltrim($html);
        $matchingResult = \preg_match(
            "/(<\/\s*" . $tag . "\s*>)/i",
            $html,
            $endOfScriptMatches
        );
        if ($matchingResult === 0) {
            return '';
        }

        $closingTag = $endOfScriptMatches[1];
        $this->value = \mb_substr($remainingHtml, 0, \mb_strpos($html, $closingTag));

        return \mb_substr(
            \mb_strstr($remainingHtml, $closingTag),
            \mb_strlen($closingTag)
        );
    }
778967
public function parse($html)
    {
        $errorHandling = libxml_use_internal_errors(true);

        $dom = new \DOMDocument();
        $dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);

        $xpath = new \DOMXpath($dom);

        foreach ($this->componentFactories as $tag => $factory) {
            $tags = $xpath->query('//' . $tag);

            if ($tags) {
                foreach ($tags as $node) {
                    $factory->parse($node);
                }
            }
        }

        libxml_clear_errors();
        libxml_use_internal_errors($errorHandling);

        return $dom->saveHTML();
    }
1190660
public static function htmlToPlainText($html)
    {
        // Replace &nbsp; with spaces
        $html = str_replace("\xC2\xA0", ' ', html_entity_decode($html));
        // Strip out HTML tags
        $text = strip_tags($html);
        // Replace excessive whitespace (spaces, tabs, and line breaks) with single space
        $text = preg_replace('/\s+/S', ' ', $text);

        return $text;
    }
53292
function markScriptToLang($html)
	{
		if ($this->onlyCoreFonts) {
			return $html;
		}

		$n = '';
		$a = preg_split('/<(.*?)>/ms', $html, -1, PREG_SPLIT_DELIM_CAPTURE);
		foreach ($a as $i => $e) {
			if ($i % 2 == 0) {

				// ignore if in Textarea
				if ($i > 0 && strtolower(substr($a[$i - 1], 1, 8)) == 'textarea') {
					$a[$i] = $e;
					continue;
				}

				$e = UtfString::strcode2utf($e);
				$e = $this->lesser_entity_decode($e);

				$earr = $this->UTF8StringToArray($e, false);

				$scriptblock = 0;
				$scriptblocks = [];
				$scriptblocks[0] = 0;
				$chardata = [];
				$subchunk = 0;
				$charctr = 0;

				foreach ($earr as $char) {

					$ucd_record = Ucdn::get_ucd_record($char);
					$sbl = $ucd_record[6];

					if ($sbl && $sbl != 40 && $sbl != 102) {
						if ($scriptblock == 0) {
							$scriptblock = $sbl;
							$scriptblocks[$subchunk] = $scriptblock;
						} elseif ($scriptblock > 0 && $scriptblock != $sbl) {
							// NEW (non-common) Script encountered in this chunk.
							// Start a new subchunk
							$subchunk++;
							$scriptblock = $sbl;
							$charctr = 0;
							$scriptblocks[$subchunk] = $scriptblock;
						}
					}

					$chardata[$subchunk][$charctr]['script'] = $sbl;
					$chardata[$subchunk][$charctr]['uni'] = $char;
					$charctr++;
				}

				// If scriptblock[x] = common & non-baseScript
				// and scriptblock[x+1] = baseScript
				// Move common script from end of x to start of x+1
				for ($sch = 0; $sch < $subchunk; $sch++) {
					if ($scriptblocks[$sch] > 0 && $scriptblocks[$sch] != $this->baseScript && $scriptblocks[$sch + 1] == $this->baseScript) {
						$end = count($chardata[$sch]) - 1;
						while ($chardata[$sch][$end]['script'] == 0 && $end > 1) { // common script
							$tmp = array_pop($chardata[$sch]);
							array_unshift($chardata[$sch + 1], $tmp);
							$end--;
						}
					}
				}

				$o = '';
				for ($sch = 0; $sch <= $subchunk; $sch++) {

					if (isset($chardata[$sch])) {
						$s = '';
						for ($j = 0; $j < count($chardata[$sch]); $j++) {
							$s .= UtfString::code2utf($chardata[$sch][$j]['uni']);
						}

						// ZZZ99 Undo lesser_entity_decode as above - but only for <>&
						$s = str_replace("&", "&amp;", $s);
						$s = str_replace("<", "&lt;", $s);
						$s = str_replace(">", "&gt;", $s);

						// Check Vietnamese if Latin script - even if Basescript
						if ($scriptblocks[$sch] == Ucdn::SCRIPT_LATIN && $this->autoVietnamese && preg_match("/([" . $this->scriptToLanguage->getLanguageDelimiters('viet') . "])/u", $s)) {
							$o .= '<span lang="vi" class="lang_vi">' . $s . '</span>';
						} elseif ($scriptblocks[$sch] == Ucdn::SCRIPT_ARABIC && $this->autoArabic) { // Check Arabic for different languages if Arabic script - even if Basescript
							if (preg_match("/[" . $this->scriptToLanguage->getLanguageDelimiters('sindhi') . "]/u", $s)) {
								$o .= '<span lang="sd" class="lang_sd">' . $s . '</span>';
							} elseif (preg_match("/[" . $this->scriptToLanguage->getLanguageDelimiters('urdu') . "]/u", $s)) {
								$o .= '<span lang="ur" class="lang_ur">' . $s . '</span>';
							} elseif (preg_match("/[" . $this->scriptToLanguage->getLanguageDelimiters('pashto') . "]/u", $s)) {
								$o .= '<span lang="ps" class="lang_ps">' . $s . '</span>';
							} elseif (preg_match("/[" . $this->scriptToLanguage->getLanguageDelimiters('persian') . "]/u", $s)) {
								$o .= '<span lang="fa" class="lang_fa">' . $s . '</span>';
							} elseif ($this->baseScript != Ucdn::SCRIPT_ARABIC && $this->scriptToLanguage->getLanguageByScript($scriptblocks[$sch])) {
								$o .= '<span lang="' . $this->scriptToLanguage->getLanguageByScript($scriptblocks[$sch]) . '" class="lang_' . $this->scriptToLanguage->getLanguageByScript($scriptblocks[$sch]) . '">' . $s . '</span>';
							} else {
								// Just output chars
								$o .= $s;
							}
						} elseif ($scriptblocks[$sch] > 0 && $scriptblocks[$sch] != $this->baseScript && $this->scriptToLanguage->getLanguageByScript($scriptblocks[$sch])) { // Identify Script block if not Basescript, and mark up as language
							// Encase in <span>
							$o .= '<span lang="' . $this->scriptToLanguage->getLanguageByScript($scriptblocks[$sch]) . '" class="lang_' . $this->scriptToLanguage->getLanguageByScript($scriptblocks[$sch]) . '">';
							$o .= $s;
							$o .= '</span>';
						} else {
							// Just output chars
							$o .= $s;
						}
					}
				}

				$a[$i] = $o;
			} else {
				$a[$i] = '<' . $e . '>';
			}
		}

		$n = implode('', $a);

		return $n;
	}
1056442
private function extractToken($html)
    {
        $token = null;

		$regex = '#<input type="hidden" name="token" value="(.*?)" />#s';

		if (preg_match($regex, $html, $matches) === 1)
		{
			$token = $matches[1];
		}

        return $token;
    }
490279
protected function parseHtml($html)
    {
        $data = [
            'image' => '',
            'title' => '',
            'description' => '',
            'pictures' => [],
        ];

        libxml_use_internal_errors(true);
        $doc = new \DOMDocument();
        $doc->loadHTML($html);

        /** @var \DOMElement $meta */
        foreach ($doc->getElementsByTagName('meta') as $meta) {
            if ($meta->getAttribute('itemprop') === 'image') {
                $data['image'] = $meta->getAttribute('content');
            } elseif ($meta->getAttribute('property') === 'og:image') {
                $data['image'] = $meta->getAttribute('content');
            } elseif ($meta->getAttribute('property') === 'twitter:image') {
                $data['image'] = $meta->getAttribute('value');
            }

            if ($meta->getAttribute('itemprop') === 'name') {
                $data['title'] = $meta->getAttribute('content');
            } elseif ($meta->getAttribute('property') === 'og:title') {
                $data['title'] = $meta->getAttribute('content');
            } elseif ($meta->getAttribute('property') === 'twitter:title') {
                $data['title'] = $meta->getAttribute('value');
            }

            if ($meta->getAttribute('itemprop') === 'description') {
                $data['title'] = $meta->getAttribute('content');
            }
            if ($meta->getAttribute('property') === 'og:description') {
                $data['description'] = $meta->getAttribute('content');
            }
        }

        if (empty($data['title'])) {
            /** @var \DOMElement $title */
            foreach ($doc->getElementsByTagName('title') as $title) {
                $data['title'] = $title->nodeValue;
            }
        }

        if (empty($data['description'])) {
            foreach ($doc->getElementsByTagName('meta') as $meta) {
                if ($meta->getAttribute('name') === 'description') {
                    $data['description'] = $meta->getAttribute('content');
                }
            }
        }

        foreach ($doc->getElementsByTagName('img') as $img) {
            $data['pictures'][] = $img->getAttribute('src');
        }

        return $data;
    }
123451
private function prepareHtmlForDomConversion($html)
    {
        $htmlWithSelfClosingSlashes = $this->ensurePhpUnrecognizedSelfClosingTagsAreXml($html);
        $htmlWithDocumentType = $this->ensureDocumentType($htmlWithSelfClosingSlashes);

        return $this->addContentTypeMetaTag($htmlWithDocumentType);
    }