Resolver.php 2.7 KB

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