136b712d8SJaap de Haan<?php 236b712d8SJaap de Haan 336b712d8SJaap de Haanclass plugin_bpmnio_link_processor 436b712d8SJaap de Haan{ 536b712d8SJaap de Haan /** 636b712d8SJaap de Haan * @return array{xml: string, links: array<string, array{href: string, target: string}>} 736b712d8SJaap de Haan */ 836b712d8SJaap de Haan public static function buildPayload(string $xml): array 936b712d8SJaap de Haan { 10*57e8c51eSJaap de Haan $xml = trim($xml); 11*57e8c51eSJaap de Haan if ($xml === '') { 1236b712d8SJaap de Haan return ['xml' => $xml, 'links' => []]; 1336b712d8SJaap de Haan } 1436b712d8SJaap de Haan 1536b712d8SJaap de Haan $document = new DOMDocument('1.0', 'UTF-8'); 1636b712d8SJaap de Haan $document->preserveWhiteSpace = true; 1736b712d8SJaap de Haan $document->formatOutput = false; 1836b712d8SJaap de Haan 1936b712d8SJaap de Haan $previous = libxml_use_internal_errors(true); 2036b712d8SJaap de Haan $loaded = $document->loadXML($xml); 2136b712d8SJaap de Haan libxml_clear_errors(); 2236b712d8SJaap de Haan libxml_use_internal_errors($previous); 2336b712d8SJaap de Haan 2436b712d8SJaap de Haan if (!$loaded) { 2536b712d8SJaap de Haan return ['xml' => $xml, 'links' => []]; 2636b712d8SJaap de Haan } 2736b712d8SJaap de Haan 2836b712d8SJaap de Haan $links = []; 2936b712d8SJaap de Haan foreach ($document->getElementsByTagName('*') as $element) { 3036b712d8SJaap de Haan if (!$element->hasAttribute('id') || !$element->hasAttribute('name')) { 3136b712d8SJaap de Haan continue; 3236b712d8SJaap de Haan } 3336b712d8SJaap de Haan 3436b712d8SJaap de Haan $parsedLink = self::parseLinkMarkup($element->getAttribute('name')); 3536b712d8SJaap de Haan if ($parsedLink === null) { 3636b712d8SJaap de Haan continue; 3736b712d8SJaap de Haan } 3836b712d8SJaap de Haan 3936b712d8SJaap de Haan $target = self::resolveTarget($parsedLink['target']); 4036b712d8SJaap de Haan if ($target === null || auth_quickaclcheck($target) < AUTH_READ) { 4136b712d8SJaap de Haan continue; 4236b712d8SJaap de Haan } 4336b712d8SJaap de Haan 4436b712d8SJaap de Haan $elementId = trim($element->getAttribute('id')); 4536b712d8SJaap de Haan if ($elementId === '') { 4636b712d8SJaap de Haan continue; 4736b712d8SJaap de Haan } 4836b712d8SJaap de Haan 4936b712d8SJaap de Haan $label = $parsedLink['label'] !== '' ? $parsedLink['label'] : $target; 5036b712d8SJaap de Haan 5136b712d8SJaap de Haan $element->setAttribute('name', $label); 5236b712d8SJaap de Haan $links[$elementId] = [ 5336b712d8SJaap de Haan 'href' => self::buildHref($target), 5436b712d8SJaap de Haan 'target' => $target, 5536b712d8SJaap de Haan ]; 5636b712d8SJaap de Haan } 5736b712d8SJaap de Haan 5836b712d8SJaap de Haan $renderXml = $document->saveXML(); 5936b712d8SJaap de Haan if ($renderXml === false) { 6036b712d8SJaap de Haan $renderXml = $xml; 6136b712d8SJaap de Haan } 6236b712d8SJaap de Haan 6336b712d8SJaap de Haan return ['xml' => $renderXml, 'links' => $links]; 6436b712d8SJaap de Haan } 6536b712d8SJaap de Haan 6636b712d8SJaap de Haan /** 6736b712d8SJaap de Haan * @return array{target: string, label: string}|null 6836b712d8SJaap de Haan */ 6936b712d8SJaap de Haan private static function parseLinkMarkup(string $value): ?array 7036b712d8SJaap de Haan { 7136b712d8SJaap de Haan $value = trim($value); 7236b712d8SJaap de Haan if (!preg_match('/^\[\[([^\]|]+)(?:\|([^\]]*))?\]\]$/', $value, $matches)) { 7336b712d8SJaap de Haan return null; 7436b712d8SJaap de Haan } 7536b712d8SJaap de Haan 7636b712d8SJaap de Haan $target = trim($matches[1]); 7736b712d8SJaap de Haan if ($target === '') { 7836b712d8SJaap de Haan return null; 7936b712d8SJaap de Haan } 8036b712d8SJaap de Haan 8136b712d8SJaap de Haan return [ 8236b712d8SJaap de Haan 'target' => $target, 8336b712d8SJaap de Haan 'label' => isset($matches[2]) ? trim($matches[2]) : '', 8436b712d8SJaap de Haan ]; 8536b712d8SJaap de Haan } 8636b712d8SJaap de Haan 8736b712d8SJaap de Haan private static function resolveTarget(string $target): ?string 8836b712d8SJaap de Haan { 8936b712d8SJaap de Haan global $ID; 9036b712d8SJaap de Haan 9136b712d8SJaap de Haan $target = trim($target); 9236b712d8SJaap de Haan if ($target === '' || preg_match('#^[a-z][a-z0-9+.-]*://#i', $target)) { 9336b712d8SJaap de Haan return null; 9436b712d8SJaap de Haan } 9536b712d8SJaap de Haan 9636b712d8SJaap de Haan if (str_starts_with($target, ':')) { 9736b712d8SJaap de Haan return self::normalizeId(trim($target, ':')); 9836b712d8SJaap de Haan } 9936b712d8SJaap de Haan 10036b712d8SJaap de Haan $baseNamespace = self::getNamespace((string) $ID); 10136b712d8SJaap de Haan if (str_starts_with($target, '.')) { 10236b712d8SJaap de Haan $segments = $baseNamespace === '' ? [] : explode(':', $baseNamespace); 10336b712d8SJaap de Haan foreach (explode(':', $target) as $segment) { 10436b712d8SJaap de Haan $segment = trim($segment); 10536b712d8SJaap de Haan if ($segment === '' || $segment === '.') { 10636b712d8SJaap de Haan continue; 10736b712d8SJaap de Haan } 10836b712d8SJaap de Haan if ($segment === '..') { 10936b712d8SJaap de Haan array_pop($segments); 11036b712d8SJaap de Haan continue; 11136b712d8SJaap de Haan } 11236b712d8SJaap de Haan $segments[] = $segment; 11336b712d8SJaap de Haan } 11436b712d8SJaap de Haan 11536b712d8SJaap de Haan return self::normalizeId(implode(':', $segments)); 11636b712d8SJaap de Haan } 11736b712d8SJaap de Haan 11836b712d8SJaap de Haan if (str_contains($target, ':')) { 11936b712d8SJaap de Haan return self::normalizeId($target); 12036b712d8SJaap de Haan } 12136b712d8SJaap de Haan 12236b712d8SJaap de Haan $pageId = $baseNamespace === '' ? $target : $baseNamespace . ':' . $target; 12336b712d8SJaap de Haan return self::normalizeId($pageId); 12436b712d8SJaap de Haan } 12536b712d8SJaap de Haan 12636b712d8SJaap de Haan private static function buildHref(string $target): string 12736b712d8SJaap de Haan { 12836b712d8SJaap de Haan return DOKU_BASE . 'doku.php?' . http_build_query(['id' => $target], '', '&', PHP_QUERY_RFC3986); 12936b712d8SJaap de Haan } 13036b712d8SJaap de Haan 13136b712d8SJaap de Haan private static function getNamespace(string $pageId): string 13236b712d8SJaap de Haan { 13336b712d8SJaap de Haan $pos = strrpos($pageId, ':'); 13436b712d8SJaap de Haan if ($pos === false) { 13536b712d8SJaap de Haan return ''; 13636b712d8SJaap de Haan } 13736b712d8SJaap de Haan 13836b712d8SJaap de Haan return substr($pageId, 0, $pos); 13936b712d8SJaap de Haan } 14036b712d8SJaap de Haan 14136b712d8SJaap de Haan private static function normalizeId(string $value): ?string 14236b712d8SJaap de Haan { 14336b712d8SJaap de Haan $value = trim($value); 14436b712d8SJaap de Haan if ($value === '') { 14536b712d8SJaap de Haan return null; 14636b712d8SJaap de Haan } 14736b712d8SJaap de Haan 14836b712d8SJaap de Haan if (function_exists('cleanID')) { 14936b712d8SJaap de Haan $value = cleanID($value); 15036b712d8SJaap de Haan } 15136b712d8SJaap de Haan 15236b712d8SJaap de Haan $segments = []; 15336b712d8SJaap de Haan foreach (explode(':', $value) as $segment) { 15436b712d8SJaap de Haan $segment = trim($segment); 15536b712d8SJaap de Haan if ($segment === '' || $segment === '.') { 15636b712d8SJaap de Haan continue; 15736b712d8SJaap de Haan } 15836b712d8SJaap de Haan if ($segment === '..') { 15936b712d8SJaap de Haan array_pop($segments); 16036b712d8SJaap de Haan continue; 16136b712d8SJaap de Haan } 16236b712d8SJaap de Haan $segments[] = $segment; 16336b712d8SJaap de Haan } 16436b712d8SJaap de Haan 16536b712d8SJaap de Haan if ($segments === []) { 16636b712d8SJaap de Haan return null; 16736b712d8SJaap de Haan } 16836b712d8SJaap de Haan 16936b712d8SJaap de Haan return implode(':', $segments); 17036b712d8SJaap de Haan } 17136b712d8SJaap de Haan} 172