You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

106 lines
2.8 KiB

  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. $id = rtrim($id, '.'); // trailing dots are invalid
  72. if ($id === '') return '';
  73. $trail = ($id[-1] === ':') ? ':' : ''; // keep trailing colon
  74. $result = [];
  75. $parts = explode(':', $id);
  76. foreach ($parts as $dir) {
  77. if ($dir === '.') continue;
  78. if ($dir === '') continue;
  79. if ($dir === '..') {
  80. array_pop($result);
  81. continue;
  82. }
  83. $result[] = $dir;
  84. }
  85. $id = implode(':', $result);
  86. $id .= $trail;
  87. return $id;
  88. }
  89. }