1<?php 2/** 3 * Plugin nspages : Displays nicely a list of the pages of a namespace 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author Guillaume Turri <guillaume.turri@gmail.com> 7 */ 8if(!defined('DOKU_INC')) die(); 9 10class namespaceFinder { 11 private $wantedNs; 12 private $isSafe; 13 14 /** 15 * Resolves the namespace on construction 16 * 17 * @param string $path the namespace link 18 */ 19 function __construct($path){ 20 $this->wantedNs = $this->computeWantedNs($path); 21 $this->sanitizeNs(); 22 } 23 24 private function computeWantedNs($wantedNS){ 25 global $ID; 26 27 // Convert all other separators to colons 28 // Nb: slashes should be accepted as separator too as they can be a legit separator when the DW conf "useslash" is on. (and anyway slashes are not allowed in page name 29 // (see https://www.dokuwiki.org/pagename ) so it's the only correct way to deal with it. 30 // But we don't need to str_replace it because we don't go through "cleanID" (which would handle it when the conf is off) and because we never remove nor escape the slashes 31 // before they are converted to a FS path 32 $wantedNS = str_replace(';', ':', $wantedNS); // accepted by DW as namespace separator according to https://www.dokuwiki.org/pagename 33 34 $result = ''; 35 if($wantedNS == '') { 36 $wantedNS = $this->getCurrentNamespace(); 37 } 38 if( $this->isRelativePath($wantedNS) ) { 39 $result = getNS($ID); 40 // normalize initial dots ( ..:..abc -> ..:..:abc ) 41 $wantedNS = preg_replace('/^((\.+:)*)(\.+)(?=[^:\.])/', '\1\3:', $wantedNS); 42 } elseif ( $this->isPageRelativePath($wantedNS) ) { 43 $result = $ID; 44 $wantedNS = substr($wantedNS, 1); 45 } 46 $result .= ':'.$wantedNS.':'; 47 return $result; 48 } 49 50 private function getCurrentNamespace(){ 51 return '.'; 52 } 53 54 private function isRelativePath($path){ 55 return $path[0] == '.'; 56 } 57 58 private function isPageRelativePath($path){ 59 return $path[0] == '~'; 60 } 61 62 /** 63 * Get rid of '..'. 64 * Therefore, provides a ns which passes the cleanid() function, 65 */ 66 private function sanitizeNs(){ 67 $ns = explode(':', $this->wantedNs); 68 69 for($i = 0; $i < count($ns); $i++) { 70 if($ns[$i] === '' || $ns[$i] === '.') { 71 array_splice($ns, $i, 1); 72 $i--; 73 } else if($ns[$i] == '..') { 74 if($i == 0) { 75 //the first can't be '..', to stay inside 'data/pages' 76 break; 77 } else { 78 //simplify the path, getting rid of 'ns:..' 79 array_splice($ns, $i - 1, 2); 80 $i -= 2; 81 } 82 } 83 } 84 85 $this->isSafe = (count($ns) == 0 || $ns[0] != '..'); 86 $this->wantedNs = implode(':', $ns); 87 } 88 89 function getWantedNs(){ 90 return $this->wantedNs; 91 } 92 93 function isNsSafe(){ 94 return $this->isSafe; 95 } 96 97 function getWantedDirectory(){ 98 return $this->namespaceToDirectory($this->wantedNs); 99 } 100 101 static function namespaceToDirectory($ns){ 102 return utf8_encodeFN(str_replace(':', '/', $ns)); 103 } 104} 105