12cd6cc0aSAndreas Gohr<?php 22cd6cc0aSAndreas Gohr 32cd6cc0aSAndreas Gohrnamespace dokuwiki\File; 42cd6cc0aSAndreas Gohr 52cd6cc0aSAndreas Gohr/** 62cd6cc0aSAndreas Gohr * Resolving relative IDs to absolute ones 72cd6cc0aSAndreas Gohr */ 82cd6cc0aSAndreas Gohrabstract class Resolver 92cd6cc0aSAndreas Gohr{ 102cd6cc0aSAndreas Gohr 112cd6cc0aSAndreas Gohr /** @var string context page ID */ 122cd6cc0aSAndreas Gohr protected $contextID; 132cd6cc0aSAndreas Gohr /** @var string namespace of context page ID */ 142cd6cc0aSAndreas Gohr protected $contextNS; 152cd6cc0aSAndreas Gohr 162cd6cc0aSAndreas Gohr /** 172cd6cc0aSAndreas Gohr * @param string $contextID the current pageID that's the context to resolve relative IDs to 182cd6cc0aSAndreas Gohr */ 192cd6cc0aSAndreas Gohr public function __construct($contextID) 202cd6cc0aSAndreas Gohr { 212cd6cc0aSAndreas Gohr $this->contextID = $contextID; 222cd6cc0aSAndreas Gohr $this->contextNS = (string)getNS($contextID); 232cd6cc0aSAndreas Gohr } 242cd6cc0aSAndreas Gohr 252cd6cc0aSAndreas Gohr /** 262cd6cc0aSAndreas Gohr * Resolves a given ID to be absolute 272cd6cc0aSAndreas Gohr * 282cd6cc0aSAndreas Gohr * @param string $id The ID to resolve 292cd6cc0aSAndreas Gohr * @param string|int|false $rev The revision time to use when resolving 302cd6cc0aSAndreas Gohr * @param bool $isDateAt Is the given revision only a datetime hint not an exact revision? 312cd6cc0aSAndreas Gohr * @return string 322cd6cc0aSAndreas Gohr */ 332cd6cc0aSAndreas Gohr public function resolveId($id, $rev = '', $isDateAt = false) 342cd6cc0aSAndreas Gohr { 352cd6cc0aSAndreas Gohr global $conf; 362cd6cc0aSAndreas Gohr 372cd6cc0aSAndreas Gohr // some pre cleaning for useslash: 382cd6cc0aSAndreas Gohr if ($conf['useslash']) $id = str_replace('/', ':', $id); 392cd6cc0aSAndreas Gohr // on some systems, semicolons might be used instead of colons: 402cd6cc0aSAndreas Gohr $id = str_replace(';', ':', $id); 412cd6cc0aSAndreas Gohr 422cd6cc0aSAndreas Gohr $id = $this->resolvePrefix($id); 4379a2d784SGerrit Uitslag return $this->resolveRelatives($id); 442cd6cc0aSAndreas Gohr } 452cd6cc0aSAndreas Gohr 462cd6cc0aSAndreas Gohr /** 472cd6cc0aSAndreas Gohr * Handle IDs starting with . or ~ and prepend the proper prefix 482cd6cc0aSAndreas Gohr * 492cd6cc0aSAndreas Gohr * @param string $id 502cd6cc0aSAndreas Gohr * @return string 512cd6cc0aSAndreas Gohr */ 522cd6cc0aSAndreas Gohr protected function resolvePrefix($id) 532cd6cc0aSAndreas Gohr { 54*c4055b85SAndreas Gohr if($id === '') return $id; 55*c4055b85SAndreas Gohr 562cd6cc0aSAndreas Gohr // relative to current page (makes the current page a start page) 572cd6cc0aSAndreas Gohr if ($id[0] === '~') { 582cd6cc0aSAndreas Gohr $id = $this->contextID . ':' . substr($id, 1); 592cd6cc0aSAndreas Gohr } 602cd6cc0aSAndreas Gohr 612cd6cc0aSAndreas Gohr // relative to current namespace 622cd6cc0aSAndreas Gohr if ($id[0] === '.') { 632cd6cc0aSAndreas Gohr // normalize initial dots without a colon 642cd6cc0aSAndreas Gohr $id = preg_replace('/^((\.+:)*)(\.+)(?=[^:\.])/', '\1\3:', $id); 652cd6cc0aSAndreas Gohr $id = $this->contextNS . ':' . $id; 662cd6cc0aSAndreas Gohr } 672cd6cc0aSAndreas Gohr 682cd6cc0aSAndreas Gohr // auto-relative, because there is a context namespace but no namespace in the ID 692cd6cc0aSAndreas Gohr if ($this->contextID !== '' && strpos($id, ':') === false) { 702cd6cc0aSAndreas Gohr $id = $this->contextNS . ':' . $id; 712cd6cc0aSAndreas Gohr } 722cd6cc0aSAndreas Gohr 732cd6cc0aSAndreas Gohr return $id; 742cd6cc0aSAndreas Gohr } 752cd6cc0aSAndreas Gohr 762cd6cc0aSAndreas Gohr /** 772cd6cc0aSAndreas Gohr * Handle . and .. within IDs 782cd6cc0aSAndreas Gohr * 792cd6cc0aSAndreas Gohr * @param string $id 802cd6cc0aSAndreas Gohr * @return string 812cd6cc0aSAndreas Gohr */ 822cd6cc0aSAndreas Gohr protected function resolveRelatives($id) 832cd6cc0aSAndreas Gohr { 842cd6cc0aSAndreas Gohr if ($id === '') return ''; 852cd6cc0aSAndreas Gohr $trail = ($id[-1] === ':') ? ':' : ''; // keep trailing colon 862cd6cc0aSAndreas Gohr 872cd6cc0aSAndreas Gohr $result = []; 882cd6cc0aSAndreas Gohr $parts = explode(':', $id); 892cd6cc0aSAndreas Gohr 902cd6cc0aSAndreas Gohr foreach ($parts as $dir) { 912cd6cc0aSAndreas Gohr if ($dir === '.') continue; 922cd6cc0aSAndreas Gohr if ($dir === '') continue; 932cd6cc0aSAndreas Gohr if ($dir === '..') { 942cd6cc0aSAndreas Gohr array_pop($result); 952cd6cc0aSAndreas Gohr continue; 962cd6cc0aSAndreas Gohr } 972cd6cc0aSAndreas Gohr array_push($result, $dir); 982cd6cc0aSAndreas Gohr } 992cd6cc0aSAndreas Gohr 1002cd6cc0aSAndreas Gohr $id = implode(':', $result); 1012cd6cc0aSAndreas Gohr $id .= $trail; 1022cd6cc0aSAndreas Gohr 1032cd6cc0aSAndreas Gohr return $id; 1042cd6cc0aSAndreas Gohr } 1052cd6cc0aSAndreas Gohr 1062cd6cc0aSAndreas Gohr} 107