bla/blub/myfile.txt // bla/blub .. myfile.txt -> bla/myfile.txt // bla/blub ../foo myfile.txt -> bla/foo/myfile.txt // bla/blub / myfile.txt -> /myfile.txt // a.s.o. // Known restriction: path components may not include directories whose names // contain dots. if ($pathPart[0] == '/') { $x = "$pathPart/$basePart"; } else { $x = "$initialPath/$pathPart/$basePart"; $x = str_replace("/./", "/", $x); while (($y = preg_replace('#[^\/\.]+/\.\./#', '', $x)) != $x) $x = $y; } $x = preg_replace('#^\./#', '', $x); $x = str_replace("//", "/", $x); return $x; } /* Storage oriented file referencing: if the given Uploads argument is a sole filename (no slashes), interpret its location being in the respective upload dir of the page where the markup is located. If a path is given and is relative, then dto.. If path is given and absolute, interpret it with respect to the upload root dir as root directory: myfile.txt -> uploads/MyGroup/MyPage/myfile.txt ./myfile.txt -> uploads/MyGroup/MyPage/myfile.txt mysubdir/myfile.txt -> uploads/MyGroup/MyPage/mysubdir/myfile.txt ../myfile.txt -> uploads/MyGroup/myfile.txt ../MyOtherPage/myfile.txt -> uploads/MyGroup/MyOtherPage/myfile.txt /MyGroup/MyPage/myfile.txt -> uploads/MyGroup/MyPage/myfile.txt /myfile.txt -> uploads/myfile.txt a.s.o. This was for upload prefix format set to /$Group/$Page. When however the default setting is used (/$Group), things behave accordingly. In particular, the default file location is in the respective group upload dir, so myfile.txt -> uploads/MyGroup/myfile.txt ../MyOtherGroup/myfile.txt -> uploads/MyOtherGroup/myfile.txt For evaluating the authorization to upload/download a file, the file must be associated to some page. If the file is located in an upload dir uploads/MyGroup/MyPage, the page MyGroup.MyPage is interpreted as "mother" page. If in uploads/MyGroup, then Mygroup.$DefaultName is used. In all other cases $DefaultGroup.$DefaultName. */ function LinkUpload_uploadmarkup($pagename, $imap, $path, $title, $txt, $fmt=NULL) { global $UploadDir, $UploadPrefixFmt, $DefaultName, $DefaultGroup, $FmtV, $LinkUploadCreateFmt, $UploadUrlFmt, $EnableDirectDownload; // Note: at this point pagename refers to the page where the markup "Uploads:" is // _located_, not where the file reference points to. Therefore infer this from the // path info in $path. $upname = MakeUploadName("DummyGroup.DummyPage", basename($path)); //pagename argument never used // get referenced dir: $initialpath = FmtPageName("$UploadPrefixFmt", $pagename); // where we start from when interpreting the path $filepath_pre = getConsolidatedPathFromParts($initialpath, dirname($path), $upname); // stop if it tries to go "over the top": if (strpos($filepath_pre, "../") !== false) return ""Uploads:" failed: Referenced file target lies beyond the allowed directory tree."; // infer referenced page to base the authorization on it: if (preg_match('#^/([^/.]+)/([^/.]+)/.*#', $filepath_pre, $matches)) { $referencedPagename = $matches[1] . '.' . $matches[2]; } else if (preg_match('#^/([^/.]+)/.*#', $filepath_pre, $matches)) { $referencedPagename = $matches[1] . '.' . $DefaultName; } else { $referencedPagename = "$DefaultGroup.$DefaultName"; } // up to here the filepath did not contain the path part to the upload root dir yet, so amend: $filepath = "$UploadDir$filepath_pre"; // note that UploadDir has a trailing slash $FmtV['$LinkUpload'] = FmtPageName("\$PageUrl?action=upload&upname=$upname", $referencedPagename); $FmtV['$LinkText'] = $txt; if (!file_exists($filepath)) return FmtPageName($LinkUploadCreateFmt, $referencedPagename); $path = PUE(FmtPageName(IsEnabled($EnableDirectDownload, 1) ? "$UploadUrlFmt/$filepath_pre" : "{\$PageUrl}?action=download&upname=$upname", $referencedPagename)); return LinkIMap($pagename, $imap, $path, $title, $txt, $fmt); }