-
- /**
- * Remove any page include tags within the given HTML.
- */
- protected function blankPageIncludes(string $html) : string
- {
- return preg_replace("/{{@\s?([0-9].*?)}}/", '', $html);
- }
-
- /**
- * Parse any include tags "{{@<page_id>#section}}" to be part of the page.
- */
- protected function parsePageIncludes(string $html) : string
- {
- $matches = [];
- preg_match_all("/{{@\s?([0-9].*?)}}/", $html, $matches);
-
- foreach ($matches[1] as $index => $includeId) {
- $fullMatch = $matches[0][$index];
- $splitInclude = explode('#', $includeId, 2);
-
- // Get page id from reference
- $pageId = intval($splitInclude[0]);
- if (is_nan($pageId)) {
- continue;
- }
-
- // Find page and skip this if page not found
- $matchedPage = Page::visible()->find($pageId);
- if ($matchedPage === null) {
- $html = str_replace($fullMatch, '', $html);
- continue;
- }
-
- // If we only have page id, just insert all page html and continue.
- if (count($splitInclude) === 1) {
- $html = str_replace($fullMatch, $matchedPage->html, $html);
- continue;
- }
-
- // Create and load HTML into a document
- $innerContent = $this->fetchSectionOfPage($matchedPage, $splitInclude[1]);
- $html = str_replace($fullMatch, trim($innerContent), $html);
- }
-
- return $html;
- }
-
-
- /**
- * Fetch the content from a specific section of the given page.
- */
- protected function fetchSectionOfPage(Page $page, string $sectionId): string
- {
- $topLevelTags = ['table', 'ul', 'ol'];
- $doc = new DOMDocument();
- libxml_use_internal_errors(true);
- $doc->loadHTML(mb_convert_encoding('<body>'.$page->html.'</body>', 'HTML-ENTITIES', 'UTF-8'));
-
- // Search included content for the id given and blank out if not exists.
- $matchingElem = $doc->getElementById($sectionId);
- if ($matchingElem === null) {
- return '';
- }
-
- // Otherwise replace the content with the found content
- // Checks if the top-level wrapper should be included by matching on tag types
- $innerContent = '';
- $isTopLevel = in_array(strtolower($matchingElem->nodeName), $topLevelTags);
- if ($isTopLevel) {
- $innerContent .= $doc->saveHTML($matchingElem);
- } else {
- foreach ($matchingElem->childNodes as $childNode) {
- $innerContent .= $doc->saveHTML($childNode);
- }
- }
- libxml_clear_errors();
-
- return $innerContent;
- }
-
- /**
- * Escape script tags within HTML content.
- */
- protected function escapeScripts(string $html) : string
- {
- if (empty($html)) {
- return $html;
- }
-
- libxml_use_internal_errors(true);
- $doc = new DOMDocument();
- $doc->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));
- $xPath = new DOMXPath($doc);
-
- // Remove standard script tags
- $scriptElems = $xPath->query('//script');
- foreach ($scriptElems as $scriptElem) {
- $scriptElem->parentNode->removeChild($scriptElem);
- }
-
- // Remove clickable links to JavaScript URI
- $badLinks = $xPath->query('//*[contains(@href, \'javascript:\')]');
- foreach ($badLinks as $badLink) {
- $badLink->parentNode->removeChild($badLink);
- }
-
- // Remove forms with calls to JavaScript URI
- $badForms = $xPath->query('//*[contains(@action, \'javascript:\')] | //*[contains(@formaction, \'javascript:\')]');
- foreach ($badForms as $badForm) {
- $badForm->parentNode->removeChild($badForm);
- }
-
- // Remove meta tag to prevent external redirects
- $metaTags = $xPath->query('//meta[contains(@content, \'url\')]');
- foreach ($metaTags as $metaTag) {
- $metaTag->parentNode->removeChild($metaTag);
- }
-
- // Remove data or JavaScript iFrames
- $badIframes = $xPath->query('//*[contains(@src, \'data:\')] | //*[contains(@src, \'javascript:\')] | //*[@srcdoc]');
- foreach ($badIframes as $badIframe) {
- $badIframe->parentNode->removeChild($badIframe);
- }
-
- // Remove 'on*' attributes
- $onAttributes = $xPath->query('//@*[starts-with(name(), \'on\')]');
- foreach ($onAttributes as $attr) {
- /** @var \DOMAttr $attr*/
- $attrName = $attr->nodeName;
- $attr->parentNode->removeAttribute($attrName);
- }
-
- $html = '';
- $topElems = $doc->documentElement->childNodes->item(0)->childNodes;
- foreach ($topElems as $child) {
- $html .= $doc->saveHTML($child);
- }
-
- return $html;
- }