1<?php 2 3namespace dokuwiki\File; 4 5/** 6 * Resolving relative IDs to absolute ones 7 */ 8abstract class Resolver 9{ 10 /** @var string context page ID */ 11 protected $contextID; 12 /** @var string namespace of context page ID */ 13 protected $contextNS; 14 15 /** 16 * @param string $contextID the current pageID that's the context to resolve relative IDs to 17 */ 18 public function __construct($contextID) 19 { 20 $this->contextID = $contextID; 21 $this->contextNS = (string)getNS($contextID); 22 } 23 24 /** 25 * Resolves a given ID to be absolute 26 * 27 * @param string $id The ID to resolve 28 * @param string|int|false $rev The revision time to use when resolving 29 * @param bool $isDateAt Is the given revision only a datetime hint not an exact revision? 30 * @return string 31 */ 32 public function resolveId($id, $rev = '', $isDateAt = false) 33 { 34 global $conf; 35 36 // some pre cleaning for useslash: 37 if ($conf['useslash']) $id = str_replace('/', ':', $id); 38 // on some systems, semicolons might be used instead of colons: 39 $id = str_replace(';', ':', $id); 40 41 $id = $this->resolvePrefix($id); 42 return $this->resolveRelatives($id); 43 } 44 45 /** 46 * Handle IDs starting with . or ~ and prepend the proper prefix 47 * 48 * @param string $id 49 * @return string 50 */ 51 protected function resolvePrefix($id) 52 { 53 if ($id === '') return $id; 54 55 // relative to current page (makes the current page a start page) 56 if ($id[0] === '~') { 57 $id = $this->contextID . ':' . substr($id, 1); 58 } 59 60 // relative to current namespace 61 if ($id[0] === '.') { 62 // normalize initial dots without a colon 63 $id = preg_replace('/^((\.+:)*)(\.+)(?=[^:\.])/', '\1\3:', $id); 64 $id = $this->contextNS . ':' . $id; 65 } 66 67 // auto-relative, because there is a context namespace but no namespace in the ID 68 if ($this->contextID !== '' && strpos($id, ':') === false) { 69 $id = $this->contextNS . ':' . $id; 70 } 71 72 return $id; 73 } 74 75 /** 76 * Handle . and .. within IDs 77 * 78 * @param string $id 79 * @return string 80 */ 81 protected function resolveRelatives($id) 82 { 83 $id = rtrim($id, '.'); // trailing dots are invalid 84 if ($id === '') return ''; 85 $trail = ($id[-1] === ':') ? ':' : ''; // keep trailing colon 86 87 $result = []; 88 $parts = explode(':', $id); 89 90 foreach ($parts as $dir) { 91 if ($dir === '.') continue; 92 if ($dir === '') continue; 93 if ($dir === '..') { 94 array_pop($result); 95 continue; 96 } 97 $result[] = $dir; 98 } 99 100 $id = implode(':', $result); 101 $id .= $trail; 102 103 return $id; 104 } 105} 106