getElementsByTagName('a'); if (!$links) { return $results; } /** @var DOMElement $link */ foreach ($links as $link) { if (!$link->hasAttribute('href')) { continue; } $href = $link->getAttribute('href'); if (Director::is_site_url($href)) { $href = Director::makeRelative($href); } // Definitely broken links. if ($href == '' || $href[0] == '/') { $results[] = [ 'Type' => 'broken', 'Target' => null, 'Anchor' => null, 'DOMReference' => $link, 'Broken' => true ]; continue; } // Link to a page on this site. $matches = []; if (preg_match('/\[sitetree_link(?:\s*|%20|,)?id=(?[0-9]+)\](#(?.*))?/i', $href ?? '', $matches)) { // Check if page link is broken /** @var SiteTree $page */ $page = DataObject::get_by_id(SiteTree::class, $matches['id']); if (!$page) { // Page doesn't exist. $broken = true; } elseif (!empty($matches['anchor'])) { // Ensure anchor isn't broken on target page $broken = !in_array($matches['anchor'], $page->getAnchorsOnPage() ?? []); } else { $broken = false; } $results[] = [ 'Type' => 'sitetree', 'Target' => $matches['id'], 'Anchor' => empty($matches['anchor']) ? null : $matches['anchor'], 'DOMReference' => $link, 'Broken' => $broken ]; continue; } // Local anchor. if (preg_match('/^#(.*)/i', $href ?? '', $matches)) { $anchor = preg_quote($matches[1] ?? '', '#'); $results[] = [ 'Type' => 'localanchor', 'Target' => null, 'Anchor' => $matches[1], 'DOMReference' => $link, 'Broken' => !preg_match("#(name|id)=\"{$anchor}\"#", $htmlValue->getContent() ?? '') ]; continue; } } return $results; } }