Or, for a slightly more
secure installation, try executing
chmod 2777 $parent
on your server and following
this link. Afterwards you can restore the permissions to
their current setting by executing
chmod $perms $parent
.";
Abort($msg);
}
## fixperms attempts to correct permissions on a file or directory
## so that both PmWiki and the account (current dir) owner can manipulate it
function fixperms($fname, $add = 0) {
clearstatcache();
if (!file_exists($fname)) Abort('no such file');
$bp = 0;
if (fileowner($fname)!=fileowner('.')) $bp = (is_dir($fname)) ? 007 : 006;
if (filegroup($fname)==filegroup('.')) $bp <<= 3;
$bp |= $add;
if ($bp && (fileperms($fname) & $bp) != $bp)
@chmod($fname,fileperms($fname)|$bp);
}
## MakePageName is used to convert a string into a valid pagename.
## If no group is supplied, then it uses $PagePathFmt to look
## for the page in other groups, or else uses the group of the
## pagename passed as an argument.
function MakePageName($basepage,$x) {
global $MakePageNameFunction, $PageNameChars, $PagePathFmt;
if (@$MakePageNameFunction) return $MakePageNameFunction($basepage,$x);
SDV($PageNameChars,'-[:alnum:]');
if (!preg_match('/(?:([^.\\/]+)[.\\/])?([^.\\/]+)$/',$x,$m)) return '';
$name=str_replace(' ', '',
preg_replace("/\\b(\\w)/e", "strtoupper('$1')",
preg_replace("/[^$PageNameChars]+/", ' ', $m[2])));
if ($m[1]) {
$group = str_replace(' ','',
preg_replace("/\\b(\\w)/e", "strtoupper('$1')",
preg_replace("/[^$PageNameChars]+/", ' ', $m[1])));
return "$group.$name";
}
foreach((array)$PagePathFmt as $pg) {
$pn = FmtPageName(str_replace('$1',$name,$pg),$basepage);
if (PageExists($pn)) return $pn;
}
$group=preg_replace('/[\\/.].*$/','',$basepage);
return "$group.$name";
}
## PCache caches basic information about a page and its attributes--
## usually everything except page text and page history. This makes
## for quicker access to certain values in FmtPageName below.
function PCache($pagename,$page) {
global $PCache;
foreach($page as $k=>$v)
if ($k!='text' && strpos($k,':')===false) $PCache[$pagename][$k]=$v;
}
## FmtPageName handles $[internationalization] and $Variable
## substitutions in strings based on the $pagename argument.
function FmtPageName($fmt,$pagename) {
# Perform $-substitutions on $fmt relative to page given by $pagename
global $GroupPattern, $NamePattern, $EnablePathInfo,
$GCount, $UnsafeGlobals, $FmtV, $FmtP, $PCache, $AsSpacedFunction;
if (strpos($fmt,'$')===false) return $fmt;
$fmt = preg_replace('/\\$([A-Z]\\w*Fmt)\\b/e','$GLOBALS[\'$1\']',$fmt);
$fmt = preg_replace('/\\$\\[(?>([^\\]]+))\\]/e',"XL(PSS('$1'))",$fmt);
$match = array('','$Group','$Name');
if (preg_match("/^($GroupPattern)[\\/.]($NamePattern)\$/", $pagename, $m))
$match = $m;
$fmt = preg_replace(array_keys($FmtP),array_values($FmtP),$fmt);
$fmt = preg_replace('!\\$ScriptUrl/([^?#\'"\\s<>]+)!e',
(@$EnablePathInfo) ? "'\$ScriptUrl/'.PUE('$1')" :
"'\$ScriptUrl?n='.str_replace('/','.',PUE('$1'))",
$fmt);
if (strpos($fmt,'$')===false) return $fmt;
static $g;
if ($GCount != count($GLOBALS)+count($FmtV)) {
$g = array();
foreach($GLOBALS as $n=>$v) {
if (is_array($v) || is_object($v) ||
isset($FmtV["\$$n"]) || in_array($n,$UnsafeGlobals)) continue;
$g["\$$n"] = $v;
}
$GCount = count($GLOBALS)+count($FmtV);
krsort($g); reset($g);
}
$fmt = str_replace(array_keys($g),array_values($g),$fmt);
$fmt = str_replace(array_keys($FmtV),array_values($FmtV),$fmt);
return $fmt;
}
## The XL functions provide translation tables for $[i18n] strings
## in FmtPageName().
function XL($key) {
global $XL,$XLLangs;
foreach($XLLangs as $l) if (isset($XL[$l][$key])) return $XL[$l][$key];
return $key;
}
function XLSDV($lang,$a) {
global $XL;
foreach($a as $k=>$v) { if (!isset($XL[$lang][$k])) $XL[$lang][$k]=$v; }
}
function XLPage($lang,$p) {
global $TimeFmt,$XLLangs,$FarmD;
$page = ReadPage($p);
if (!$page) return;
$text = preg_replace("/=>\\s*\n/",'=> ',@$page['text']);
foreach(explode("\n",$text) as $l)
if (preg_match('/^\\s*[\'"](.+?)[\'"]\\s*=>\\s*[\'"](.+)[\'"]/',$l,$match))
$xl[stripslashes($match[1])] = stripslashes($match[2]);
if (isset($xl)) {
if (@$xl['xlpage-i18n']) {
$i18n = preg_replace('/[^-\\w]/','',$xl['xlpage-i18n']);
include_once("$FarmD/scripts/xlpage-$i18n.php");
}
if ($xl['Locale']) setlocale(LC_ALL,$xl['Locale']);
if ($xl['TimeFmt']) $TimeFmt=$xl['TimeFmt'];
array_unshift($XLLangs,$lang);
XLSDV($lang,$xl);
}
}
## class PageStore holds objects that store pages via the native
## filesystem.
class PageStore {
var $dirfmt;
function PageStore($d='$WorkDir/$FullName') { $this->dirfmt=$d; }
function read($pagename) {
$newline = "\262";
$pagefile = FmtPageName($this->dirfmt,$pagename);
if ($pagefile && $fp=@fopen($pagefile,"r")) {
while (!feof($fp)) {
$line = fgets($fp,4096);
while (substr($line,-1,1)!="\n" && !feof($fp))
{ $line .= fgets($fp,4096); }
@list($k,$v) = explode('=',rtrim($line),2);
if ($k=='newline') { $newline=$v; continue; }
$page[$k] = str_replace($newline,"\n",$v);
}
fclose($fp);
}
return @$page;
}
function write($pagename,$page) {
global $Now,$Version,$Newline;
$page['name'] = $pagename;
$page['time'] = $Now;
$page['host'] = $_SERVER['REMOTE_ADDR'];
$page['agent'] = @$_SERVER['HTTP_USER_AGENT'];
$page['rev'] = @$page['rev']+1;
unset($page['version']); unset($page['newline']);
$s = false;
$pagefile = FmtPageName($this->dirfmt,$pagename);
$dir = dirname($pagefile); mkdirp($dir);
if (!file_exists("$dir/.htaccess") && $fp = @fopen("$dir/.htaccess", "w"))
{ fwrite($fp, "Order Deny,Allow\nDeny from all\n"); fclose($fp); }
if ($pagefile && ($fp=fopen("$pagefile,new","w"))) {
$s = true && fputs($fp,"version=$Version\nnewline=$Newline\n");
foreach($page as $k=>$v)
if ($k>'') $s = $s&&fputs($fp,str_replace("\n",$Newline,"$k=$v")."\n");
$s = fclose($fp) && $s;
if (file_exists($pagefile)) $s = $s && unlink($pagefile);
$s = $s && rename("$pagefile,new",$pagefile);
}
$s && fixperms($pagefile);
if (!$s)
Abort("Cannot write page to $pagename ($pagefile)...changes not saved");
}
function exists($pagename) {
$pagefile = FmtPageName($this->dirfmt,$pagename);
return ($pagefile && file_exists($pagefile));
}
function delete($pagename) {
global $Now;
$pagefile = FmtPageName($this->dirfmt,$pagename);
@rename($pagefile,"$pagefile,$Now");
}
function ls($pats=NULL) {
global $GroupPattern, $NamePattern;
$pats=(array)$pats;
array_unshift($pats, "/^$GroupPattern\.$NamePattern$/");
$dir = FmtPageName($this->dirfmt,'');
$dirlist = array(preg_replace('!/?[^/]*\$.*$!','',$dir));
$out = array();
while (count($dirlist)>0) {
$dir = array_shift($dirlist);
$dfp = opendir($dir); if (!$dfp) continue;
while (($pagefile=readdir($dfp))!=false) {
if ($pagefile{0} == '.') continue;
if (is_dir("$dir/$pagefile"))
{ array_push($dirlist,"$dir/$pagefile"); continue; }
if (@$seen[$pagefile]++) continue;
foreach($pats as $p) {
if ($p{0} == '!') {
if (preg_match($p,$pagefile)) continue 2;
} else if (!preg_match($p,$pagefile)) continue 2;
}
$out[] = $pagefile;
}
}
return $out;
}
}
function ReadPage($pagename) {
# read a page from the appropriate directories given by $WikiReadDirsFmt.
global $WikiLibDirs,$Now;
Lock(1);
foreach ($WikiLibDirs as $dir) {
$page = $dir->read($pagename);
if ($page) break;
}
if (@!$page['time']) $page['time']=$Now;
return $page;
}
function WritePage($pagename,$page) {
global $WikiDir,$LastModFile;
$WikiDir->write($pagename,$page);
if ($LastModFile) { touch($LastModFile); fixperms($LastModFile); }
}
function PageExists($pagename) {
global $WikiLibDirs;
static $pe;
if (!isset($pe[$pagename])) {
$pe[$pagename] = false;
foreach((array)$WikiLibDirs as $dir)
if ($dir->exists($pagename)) { $pe[$pagename] = true; break; }
}
return $pe[$pagename];
}
function ListPages($pat=NULL) {
global $WikiLibDirs;
foreach((array)$WikiLibDirs as $dir)
$out = array_unique(array_merge($dir->ls($pat),(array)@$out));
return $out;
}
function RetrieveAuthPage($pagename,$level,$authprompt=true) {
global $AuthFunction;
SDV($AuthFunction,'BasicAuth');
if (!function_exists($AuthFunction)) return ReadPage($pagename);
return $AuthFunction($pagename,$level,$authprompt);
}
function Abort($msg) {
# exit pmwiki with an abort message
echo "
PmWiki can't process your request
$msg
We are sorry for any inconvenience.
";
exit;
}
function Redirect($pagename,$urlfmt='$PageUrl') {
# redirect the browser to $pagename
global $EnableRedirect,$RedirectDelay;
Lock(0);
SDV($RedirectDelay,0);
clearstatcache();
#if (!PageExists($pagename)) $pagename=$DefaultPage;
$pageurl = FmtPageName($urlfmt,$pagename);
if (IsEnabled($EnableRedirect,1) &&
(!isset($_REQUEST['redirect']) || $_REQUEST['redirect'])) {
header("Location: $pageurl");
header("Content-type: text/html");
echo "
Redirect";
} else echo "Redirect to $pageurl";
exit;
}
function PrintFmt($pagename,$fmt) {
global $HTTPHeaders,$FmtV;
if (is_array($fmt))
{ foreach($fmt as $f) PrintFmt($pagename,$f); return; }
if ($fmt == 'headers:') {
foreach($HTTPHeaders as $h) (@$sent++) ? @header($h) : header($h);
return;
}
$x = FmtPageName($fmt,$pagename);
if (strncmp($fmt, 'function:', 9) == 0 &&
preg_match('/^function:(\S+)\s*(.*)$/s', $x, $match) &&
function_exists($match[1]))
{ $match[1]($pagename,$match[2]); return; }
if (strncmp($fmt, 'file:', 5) == 0 && preg_match("/^file:(.+)/s",$x,$match)) {
$filelist = preg_split('/[\\s]+/',$match[1],-1,PREG_SPLIT_NO_EMPTY);
foreach($filelist as $f) {
if (file_exists($f)) { include($f); return; }
}
return;
}
Lock(0);
if (preg_match("/^markup:(.*)$/",$x,$match))
{ print MarkupToHTML($pagename,$match[1]); return; }
if (preg_match('/^wiki:(.+)$/',$x,$match))
{ PrintWikiPage($pagename,$match[1]); return; }
echo $x;
}
function PrintWikiPage($pagename,$wikilist=NULL) {
if (is_null($wikilist)) $wikilist=$pagename;
$pagelist = preg_split('/\s+/',$wikilist,-1,PREG_SPLIT_NO_EMPTY);
foreach($pagelist as $p) {
if (PageExists($p)) {
$page = RetrieveAuthPage($p,'read',false);
if ($page['text'])
echo MarkupToHTML($pagename,$page['text']);
return;
}
}
}
function Keep($x,$level='') {
# Keep preserves a string from being processed by wiki markups
global $KeepToken,$KPV,$KPCount;
$KPCount++; $KPV[$KPCount.$level]=$x;
return $KeepToken.$KPCount.$level.$KeepToken;
}
function CondText($pagename,$condspec,$condtext) {
global $Conditions;
if (!preg_match("/^(\\S+)\\s*(!?)\\s*(\\S+)?\\s*(.*?)\\s*$/",
$condspec,$match)) return '';
@list($condstr,$condtype,$not,$condname,$condparm) = $match;
if (isset($Conditions[$condname])) {
$tf = @eval("return (".$Conditions[$condname].");");
if (!$tf xor $not) $condtext='';
}
return $condtext;
}
function IncludeText($pagename,$inclspec) {
global $MaxIncludes,$IncludeBadAnchorFmt,$InclCount,$FmtV;
SDV($MaxIncludes,50);
SDV($IncludeBadAnchorFmt,"include:\$FullName - #\$BadAnchor \$[not found]\n");
$npat = '[[:alpha:]][-\\w]*';
if ($InclCount++>=$MaxIncludes) return Keep($inclspec);
if (preg_match("/^include\\s+([^#\\s]+)(.*)$/",$inclspec,$match)) {
@list($inclstr,$inclname,$opts) = $match;
$inclname = MakePageName($pagename,$inclname);
if ($inclname==$pagename) return '';
$inclpage=RetrieveAuthPage($inclname,'read',false);
$itext=@$inclpage['text'];
foreach(preg_split('/\\s+/',$opts) as $o) {
if (preg_match("/^#($npat)?(\\.\\.)?(#($npat)?)?$/",$o,$match)) {
@list($x,$aa,$dots,$b,$bb)=$match;
if (!$dots && !$b) $bb=$npat;
if ($b=='#') $bb=$npat;
if ($aa)
$itext=preg_replace("/^.*?([^\n]*\\[\\[#$aa\\]\\])/s",'$1',$itext,1);
if ($bb)
$itext=preg_replace("/(.)[^\n]*\\[\\[#$bb\\]\\].*$/s",'$1',$itext,1);
continue;
}
if (preg_match('/^(lines?|paras?)=(\\d*)(\\.\\.(\\d*))?$/',
$o,$match)) {
@list($x,$unit,$a,$dots,$b) = $match;
$upat = ($unit{0} == 'p') ? ".*?(\n\\s*\n|$)" : "[^\n]*\n";
if (!$dots) { $b=$a; $a=0; }
if ($a>0) $a--;
$itext=preg_replace("/^(($upat)\{0,$b}).*$/s",'$1',$itext,1);
$itext=preg_replace("/^($upat)\{0,$a}/s",'',$itext,1);
continue;
}
}
return htmlspecialchars($itext,ENT_NOQUOTES);
}
return Keep($inclspec);
}
function Block($b) {
global $BlockMarkups,$HTMLVSpace,$HTMLPNewline,$MarkupFrame;
$cs = &$MarkupFrame[0]['cs']; $vspaces = &$MarkupFrame[0]['vs'];
if (!$b) $b='p,1';
@list($code,$depth) = explode(',',$b);
$out = ($code=='p' && @$cs[0]=='p') ? $HTMLPNewline : '';
if ($code=='vspace') {
$vspaces.="\n";
if (@$cs[0]!='p') return;
}
if ($depth==0) $depth=strlen($depth);
while (count($cs)>$depth)
{ $c = array_pop($cs); $out .= $BlockMarkups[$c][2]; }
if ($depth>0 && $depth==count($cs) && $cs[$depth-1]!=$code)
{ $c = array_pop($cs); $out .= $BlockMarkups[$c][2]; }
while (count($cs)>0 && $cs[count($cs)-1]!=$code &&
@$BlockMarkups[$cs[count($cs)-1]][3]==0)
{ $c = array_pop($cs); $out .= $BlockMarkups[$c][2]; }
if ($vspaces) {
$out .= (@$cs[0]=='pre') ? $vspaces : $HTMLVSpace;
$vspaces='';
}
if ($depth==0) { return $out; }
if ($depth==count($cs)) { return $out.$BlockMarkups[$code][1]; }
while (count($cs)<$depth-1)
{ array_push($cs,'dl'); $out .= $BlockMarkups['dl'][0].'