%d%d'; return sprintf( $xmlFormat, (string)$data['id'], escapeTextValue($data['title_to_index']), escapeTextValue($data['body']), escapeTextValue($data['namespace']), escapeTextValue($data['pagename']), (int)$data['level'], (int)$data['modified'] ); } /** * Clean text for CDATA inclusion * * @param string $value * @return string */ function escapeTextValue($value) { if ($value === "" || $value === null) return ""; $value = str_replace("]]>", "]]>", $value); return stripInvalidXml($value); } /** * Remove characters that are invalid in XML 1.0 * * @param string $value * @return string */ function stripInvalidXml(string $value): string { if (empty($value)) return ""; $value = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/u', '', $value); $value = mb_convert_encoding($value, 'UTF-8', 'UTF-8'); return preg_replace( '/[^\x{0009}\x{000a}\x{000d}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]/u', ' ', $value ); } /** * Extract sections based on Heading metadata */ function getDocumentsByHeadings($id, $metadata) { if (empty($metadata) || empty($metadata['description']['tableofcontents'])) { return false; } $sections = []; $level = 1; $previous_title = ''; foreach ($metadata['description']['tableofcontents'] as $row) { $sections[$row['hid']] = [ 'section' => getSectionByTitleLevel($id, $row['title']), 'level' => $row['level'], 'title' => $row['title'] ]; if ($row['level'] > $level && !empty($previous_title)) { $sections[$row['hid']]['title_text'] = $previous_title . " ยป " . $row['title']; } else { $sections[$row['hid']]['title_text'] = $row['title']; $previous_title = $row['title']; } $sections[$row['hid']]['title_to_index'] = $row['title']; } return $sections; } /** * Regex based section extraction */ function getSectionByTitleLevel($id, $header, $extended = false) { $headerReg = preg_quote($header, '/'); $file = wikiFN($id); if (!file_exists($file)) return ''; $doc = io_readFile($file); $regex = "(={1,6})\s*({$headerReg})\s*(={1,6})"; $section = ''; if (preg_match("/$regex/i", $doc, $matches)) { $startHeader = $matches[0]; $startHeaderPos = strpos($doc, $startHeader) + strlen($startHeader); $endDoc = substr($doc, $startHeaderPos); $endRegex = '(={4,6})(.*?)(={4,6})'; if (preg_match("/$endRegex/i", $endDoc, $matches)) { $endHeader = $matches[0]; $endHeaderPos = strpos($doc, $endHeader); } else { $endHeaderPos = 0; } if ($endHeaderPos) { $section = substr($doc, $startHeaderPos, $endHeaderPos - $startHeaderPos); } else { $section = substr($doc, $startHeaderPos); } } $section = trim($section); if ($extended && empty($section) && isset($endHeader)) { $startHeaderPos = $endHeaderPos + strlen($endHeader); $endDoc = substr($doc, $startHeaderPos); if (preg_match("/$endRegex/i", $endDoc, $matches)) { $nextEndHeaderPos = strpos($doc, $matches[0], $startHeaderPos); $section = substr($doc, $startHeaderPos, $nextEndHeaderPos - $startHeaderPos); } else { $section = substr($doc, $startHeaderPos); } } return trim($section); } /** * Modernized section extractor using DokuWiki internal parser helpers */ function getSection($id, $header) { static $cacheInstructions = []; static $cacheDoc = []; if (empty($cacheDoc[$id])) { $file = wikiFN($id); if (!file_exists($file)) return ''; $doc = io_readFile($file); $instructions = p_get_instructions($doc); $cacheInstructions[$id] = $instructions; $cacheDoc[$id] = $doc; } else { $instructions = $cacheInstructions[$id]; $doc = $cacheDoc[$id]; } $inSection = false; $startPos = 0; $endPos = 0; foreach ($instructions as $instruction) { if (!$inSection) { if ($instruction[0] == 'header' && trim($instruction[1][0]) == $header) { $startPos = $instruction[2]; $inSection = true; } } else { if ($instruction[0] == 'section_close' || $instruction[0] == 'header') { $endPos = $instruction[2]; break; } } } $doc = "\n" . str_replace("\r\n", "\n", $doc) . "\n"; return substr($doc, $startPos, ($endPos - $startPos)); } /** * Robust way to get searchable plain text by using XHTML and stripping noise */ function get_clean_text($wikitext) { $info = []; $html = @p_render('xhtml', p_get_instructions($wikitext), $info); $html = preg_replace('/.*?<\/span>/', '', $html); $html = preg_replace('/
.*?<\/div>/s', '', $html); $html = preg_replace('/
.*?<\/div>/s', '', $html); $text = strip_tags($html); return htmlspecialchars_decode($text); }