$SiteGroup.FoxConfig
Please move the page to $SiteAdminGroup.FoxConfig! ";
// Search path for fox.css files, if any.
if (!isset($FarmPubDirUrl)) $FarmPubDirUrl = $PubDirUrl;
SDV($FoxPubListFmt, array (
"pub/fox/fox.css" => "$PubDirUrl/fox/fox.css",
"$FarmD/pub/fox/fox.css" => "$FarmPubDirUrl/fox/fox.css" ));
# load special styles for edit/delete button and links and for message classes
foreach((array)$FoxPubListFmt as $k=>$v) {
if (file_exists(FmtPageName($k,$pagename))) {
$HTMLHeaderFmt['fox'][] =
"\n";
break;
}
} //}}}
//conditionals for edit forms
$Conditions['foxpreview'] = '(boolean)$_POST["preview"]';
$Conditions['foxcheck'] =
$Conditions['foxerror'] = 'FoxCheckErrorCond($condparm) == 1';
function FoxCheckErrorCond($arg) {
global $FoxCheckError;
if (!$arg) return (boolean)$FoxCheckError;
$arg = ParseArgs($arg);
if ($arg[''][0] != $_POST["foxname"]) return '';
if (in_array($arg[''][1], $FoxCheckError)) return 1;
} //}}}
## (:foxform #section :) or (:foxform FormPage#section :) for loading Fox forms
## #section is retrieved from page(s) given with $FoxFormsFmt.
## $FoxFormsFmt can be array of page names.
Markup('foxform', '>if', '/\\(:foxform\\s+(\\S.*?):\\)/i', "FoxLoadForm");
function FoxLoadForm($m) {
global $FoxFormsFmt;
extract($GLOBALS['MarkupToHTML']);
$list = (is_array($FoxFormsFmt)) ? $FoxFormsFmt : array($FoxFormsFmt);
$text = RetrieveAuthSection($pagename, $m[1], $list, 'read');
if (!$text) return "%red%Fox form [[$args]] is missing";
return PRR(PVSE($text));
} //}}}
//(:fox formname ....:) main form markup, starts a fox form
Markup('fox','directives','/\(:fox ([\\w]+)\\s?(.*?):\)/i',"FoxMarkup");
## Creates the HTML code for the (:fox name [placement] [parameters]:) directive
function FoxMarkup($m) {
extract($GLOBALS['MarkupToHTML']);
$PageUrl = PageVar($pagename, '$PageUrl');
static $cnt = 0; $cnt++;
$defaults = array();
$name = $m[1];
$args = ParseArgs($m[2]);
if (!isset($args['put']))
$args['put'] = (isset($args[''][0])) ? $args[''][0] : 'bottom';
$opt = array_merge($defaults, $args);
if (isset($opt['redirect'])) { $opt['redir'] = $opt['redirect']; unset($opt['redirect']);}
$javacheck = (isset($opt['formcheck']) ? FoxJSFormCheck($opt['formcheck']) : '');
$out = $javacheck;
$out.= "
TEMPL=";//DEBUG// //do var replacements on template, skip for 'copy' if ($template && $act!='copy') $template = FoxTemplateEngine($tn, $template, $fx, $tg, '','FoxProcessTargets'); } //display only, no text save to target. Needs (:foxdisplay...:) as page location for output if ($act == 'display') { $FoxDisplayFmt = $template; } //preview for foxedit if (isset($fx['preview']) && isset($_SESSION['foxedit'][$pagename])) { $FoxDisplayFmt = ''; if($template && ($act=='add' || $act=='replace')) { $InputValues['text'] = $template; $FoxDisplayFmt = $template; } if(function_exists(FoxHandleEdit)) FoxHandleEdit($pagename); continue 2; //next target page } //newedit if ($act == 'newedit') { FoxNewEdit($pagename, $template, $fx, $tg); //ends process } //add, replace, ptv, copy: load page file for saving if ($act=='add' || $act=='replace' || $act=='ptv' || $act=='copy') { //open page for first of foxactions if ($idx==0) { Lock(2); $page = RetrieveAuthPage($tn, $FoxAuth, true); //DEBUG if($FoxDebug) echo "LOAD PAGE $tn
".$template."
ADD NEW TEXT=";//DEBUG// //add line breaks as needed $temp = $pre.$template.$aft; // do string insert or repacement $text = substr_replace($text, $temp, $pos, 0); //DEBUG// if($FoxDebug>5) echo "
".$template."
FULL TEXT=";//DEBUG// return $text; } //}}} ## replace text with processed template text at position defined by put, or mark and endmark function FoxReplaceText( $pn, $text, $template, $fx, $tg ) { global $FoxDebug, $FoxMsgFmt; if($FoxDebug) echo " FoxReplaceText>"; //DEBUG// //get array with mark & form positions $ms = FoxSetMarks($pn, $text, $fx, $tg); $mark = (isset($ms[0]['mark']) ? $ms[0]['mark'] : ''); switch ($ms['put']) { case 'string' : if (!isset($ms['Mpos'])) { $FoxMsgFmt[]="$[Error: No string to find!]"; break; } else $text = substr_replace($text, $template, $ms['Mpos'], $ms['Mlen']); break; case 'all': $tlen = strlen($template); $i = 0; $icnt = count($ms[0]['pos']); while($i < $icnt) { $ipos = $ms[0]['pos'][$i] + $i*($tlen-$ms[0]['len']); $text = substr_replace($text, $template, $ipos, $ms[0]['len']); $i++; } break; case 'allplus' : $text = str_replace($mark, $template, $text); break; case 'regex' : $text = preg_replace("/$mark/", $template, $text); break; case 'marktomark': if ( $ms['Npos'] < $ms['Mpos'] ) {$FoxMsgFmt[]="$[Error: could not find endmark!]"; break;} else { $ipos = $ms['Mpos'] + $ms['Mlen']; $ilen = $ms['Npos'] - $ipos; $text = substr_replace($text, $template, $ipos, $ilen); break; } case 'overwrite' : $text = $template; break; default: $FoxMsgFmt[] = "$[Error:] '{$ms['put']}' $[is not a valid option with 'replace'!] "; } //DEBUG// if($FoxDebug>5) echo "
".$text."
FULL TEXT=".$text."";//DEBUG// return $text; } //}}} ## claculate and set mark positions, excluding positions in fox forms and overlappings function FoxSetMarks($pn, $text, $fx, $tg) { global $FoxDebug; if($FoxDebug>6) echo "
\$fx mv "; print_r($mv); echo "\$marks "; print_r($marks); echo ""; } //get any form positions and exclude marks found in any forms if (preg_match_all("/(\\(:fox\\s+([\\w]+)(?: *\\n)?)(.*?)(\\(:foxend \\2:\\))/s", $text, $matches, PREG_OFFSET_CAPTURE)) { $forms = array(); foreach((array)$matches[0] as $i => $frm ) { //build forms array: [0] = form start pos, [1] = form end pos $forms[$i][0] = $frm[1]; $forms[$i][1] = $frm[1] + strlen($frm[0]); //calculate form position of calling form if ($formname == $matches[2][$i][0]) { $ms['Fpos'] = $frm[1]; $ms['Flen'] = strlen($frm[0]); } } // add end-of-text dummy to help calculate positions near end of text $txe = strlen($text)+1; $forms[] = array( $txe, $txe); } //calculate all positions outside forms if(!isset($forms)) $forms = ''; foreach($marks as $m=>$mm) { $mk = FoxExcludeFormPos($mm, $forms); foreach ($mk as $i=>$item) { $ms[$m]['pos'][$i] = $item[0]; } } //exclude formoverlapping mark to endmark positions if(isset($ms[1]['pos'])) { foreach($ms[0]['pos'] as $m=>$mm) { foreach($ms[1]['pos'] as $n=>$nn) { if ($mm>$nn) continue; $nms[] = array($mm,$nn); } } $mk2 = FoxExcludeFormPos($nms, $forms); foreach ($mk2 as $i=>$item) { $ms[0]['pos'][$i] = $item[0]; $ms[1]['pos'][$i] = $item[1]; } } //set mark position if (isset($ms[0]['pos'][0])) { $ms['Mpos'] = $ms[0]['pos'][0]; $ms['Mlen'] = $ms[0]['len']; } //set endmark position if (isset($ms[1]['pos'])) { foreach($ms[1]['pos'] as $i => $v) { $ms['Npos'] = $v; break; } $ms['Nlen'] = $ms[1]['len']; } $ms['Tlen'] = strlen($text); //DEBUG// if($FoxDebug>6) { echo "
\$ms "; print_r($ms); echo ""; } return $ms; } //}}} ## exclude mark positions inside fox forms function FoxExcludeFormPos($marks, $forms) { $mark = array(); foreach($marks as $k=>$m) { if ($forms=='') { $mark[$k] = array($m[0],$m[1]); continue; } foreach($forms as $d=>$f) { if ($f[0]>$m[0] && $f[0]<$m[1]) continue 2; if ($m[1]<$f[0]) { $mark[] = array($m[0],$m[1]); continue 2; } if ($m[1]<$f[1]) continue 2; } } return $mark; } //}}} ## modified function TextSection to return section and position as well function FoxTextSection($text, $sections, $args = NULL) { $args = (array)$args; $npat = '[[:alpha:]][-\\w*]*'; if (!preg_match("/#($npat)?(\\.\\.)?(#($npat)?)?/", $sections, $match)) return $text; @list($x, $aa, $dots, $b, $bb) = $match; if (!$dots && !$b) $bb = $npat; if ($aa) { $pos = strpos($text, "[[#$aa]]"); if ($pos === false) return false; if (@$args['anchors']) while ($pos > 0 && $text[$pos-1] != "\n") $pos--; else $pos += strlen("[[#$aa]]"); $text = substr($text, $pos); } if ($bb) { $text = preg_replace("/(\n)[^\n]*\\[\\[#$bb\\]\\].*$/s", '$1', $text, 1); } $tsections = array('text' => $text, 'pos' => $pos); return $tsections; } //}}} ## variable substitutions of template ## see also notes on FoxDocumentation/TemplateMarkup function FoxTemplateEngine($pn, $template, $fx, $tg, $linekeyseed=NULL, $caller=NULL) { global $FoxDebug; if($FoxDebug) echo " FoxTemplateEngine> "; //DEBUG// global $EnablePostDirectives, $FoxFxSafeKeys; if($template=="") return ''; // create the data to be added, from template and variables $string = $template; // handle the {$$name[]} variables. $result = array(); $parts = explode('{[foxsection]}',$string); foreach($parts as $section) { //find all occurences of {$$name[]} if( preg_match_all('/\\{\\$\\$([A-Za-z][-_:.\\w]*)\\[\\]\\}/',$section, $matches)) { $names = array_unique($matches[1]); $max = 0; $keys = array(); $vals = array(); foreach($names as $i=>$var) { //get value $val = (array)$fx[$var]; $max = max($max,count($val)); $keys[$i] = '{$$'.$var.'[]}'; $vals[$i] = $val; } $reps = array(); for($i=0; $i < $max; $i++) { foreach((array)$vals as $k=>$val) $reps[$i][$k] = $val[$i]; } //if more than one target page, map vars to target index if ($tg['t_count']>1) { $result[] = str_replace($keys, $reps[$tg['t_idx']], $section); //for one target build repeated sections } else for ($i=0; $i < $max; $i++) { $result[] = str_replace($keys,$reps[$i],$section); } } else $result[] = $section; } // replace {$$var}, {$$var[num]} and {$$(func...)} markup. $result = FoxTemplateVarReplace($pn, $fx, $tg, $result); //replace {$$$...} with {$$...} for posting of forms with replacement vars $result = str_replace('{$$$','{$$',$result); //replace {=$$....} and {PageName=$$...} with {=$....} and {PageName=$...} for template posting $result = preg_replace('/(\\{\\*|!?[-\\w.\\/\\x80-\\xff]*)=\\$(\\$:?\\w+\\})/',"$1=$2",$result); //replace \n by newlines $result = preg_replace('/\\\\n/',"\n",$result); //create a unique linekeyseed, if necessary if ($linekeyseed==NULL) { $time1 = date('ymd-His', time() - date('Z')); $linekeyseed = $time1.'-'.rand(0,100000); #$linekeyseed = time().'a'.rand(0,100000); } foreach ($result as $index => $entry) { //skip if delete link already exists if (preg_match("/\\{\\[foxdel([^]]+)FullName\\}\\s*\\]\\}/", $entry)) continue; $linekey = $linekeyseed.''.$index; //adding linekey + pagename to any foxdelete markup for unique id if (preg_match("/button/", $entry)) { // Add linekey to delete button for line delete $entry = str_replace( '{[foxdelline button', "{[foxdelline button $linekey {\$FullName} ", $entry ); // Add linekey to delete button for range delete $entry = str_replace( '{[foxdelrange button', "{[foxdelrange button $linekey {\$FullName} ", $entry ); } else { // Add linekey to delete link for line delete $entry = str_replace( '{[foxdelline', "{[foxdelline $linekey {\$FullName} ", $entry ); // Add linekey to delete link for range delete $entry = str_replace( '{[foxdelrange', "{[foxdelrange $linekey {\$FullName} ", $entry ); } //Add line-key to delete range begin marker $entry = str_replace( '#foxbegin#', "#foxbegin $linekey#", $entry ); // Add line-key to delete range end marker $entry = str_replace( '#foxend#', "#foxend $linekey#", $entry ); $result[$index] = $entry; } return implode("\n",$result); } //}}} ## fields to be ignored in initial variable replacements SDVA($FoxFxSafeKeys, array( 'n','foxpage','action','foxaction','foxname','post', 'put', 'foxfields',':foxaction',':fulltarget',':put',':foxfields', 'foxtemplate', 'foxpreviewtemplate', 'foxdisplaytemplate', )); ## input field var replacements, exclude fields we know are not variables function FoxInputVarReplace($pn, &$fx) { global $FoxDebug; if($FoxDebug) echo "
IN-arr> ".$key."[".$i."] = ".$val."";//DEBUG// $fx[$key][$i] = FoxVarReplace($pn,$fx,'',$val); } } } else if (strstr($value, '{$$')) { if($FoxDebug>3) echo "
IN-str> ".$key." = ".$value."";//DEBUG// $fx[$key] = FoxVarReplace($pn,$fx,'',$value); } } } //}}} ## replace any {$$var} or {$$(func...)} in $arg using values from $fx function FoxTemplateVarReplace($pn, $fx, $tg, $args) { global $FoxDebug; if($FoxDebug) echo "
VREP="; //DEBUG// # {$$:ptv} $str = preg_replace('/\\$\\$:/', '$$ptv_', $str); # {$$var} $str = preg_replace_callback('/\\{\\$\\$([a-z][-_\\w]*)\\}/i', function($m) use($fx,$tg) { return FoxValue($fx,$tg,$m[0],$m[1]);}, $str); # {$$var[]} $str = preg_replace_callback('/\\{\\$\\$([a-z][-_\\w]*)\\[\\s*([a-z0-9]+)\\s*\\]\\}/i', function($m) use($fx,$tg) { return FoxValue($fx,$tg,$m[0],$m[1],$m[2]);}, $str); # {=$pagevar} $str = preg_replace_callback('/\\{(\\*|!?[-\\w.\\/\\x80-\\xff]*)\\=(\\$:?\\w+)\\}/', function($m) use($pn) { return PVSE(PageVar($pn, $m[2], $m[1]));}, $str); # {$$(date)} $str = preg_replace_callback('/\\{\\$\\$\\(date[:\\s]+(.*?)\\)\\}/', function($m) { return date($m[1]);}, $str); # {$$(timestamp)} $str = preg_replace('/\\{\\$\\$\\(timestamp\\)\\}/', $Now, $str); # {$$(expr)} $str = preg_replace_callback('/\\{\\$\\$(\\(\\w+\\b.*?\\))\\}/', function($m) use($pn) { return MarkupExpression($pn, $m[1]);}, $str); if($FoxDebug>4) echo "
".$str."
VNEW="; //DEBUG// return $str; } //}}} # looks up a field name and returns its value for {$$field} and {$$field[num]} # either strings or arrays. The final optional parameter is the value of num. If # num isn't given, and the field is an array, it uses the value of $tg['t_idx'] # (index of targetpage process) if it exists, or else 0. # In the InputVarReplace process if the field is an array, a comma-separated list of # the array elements will be returned (not just the first array element) function FoxValue($fx, $tg, $fullvar, $var, $idx=NULL) { global $FoxDebug; if($FoxDebug>2) { if(is_null($idx)) echo "
".$str."
VALUE(".$var.")="; else echo "VALUE(".$var."[".$index."])=";}//DEBUG//
$fti = 'none';
if ($tg && $tg['t_count']>1) $fti = $tg['t_idx'];
if (array_key_exists($var, $fx) ) {
$val = $fx[$var];
if(is_array($val) ) {
if ($fti==='none' && is_null($idx))
$val = implode(',',$val);
elseif (is_null($idx) )
$val = $val[$fti];
else
$val = $val[$idx];
}
//DEBUG//
if($GLOBALS['FoxDebug']>2) {
if (is_null($idx) && $fti==='none') echo "VALUE(".$var.")=".$val."";
else if (is_null($idx)) echo "VALUE(".$var."[".$fti."])=".$val."";
else echo "VALUE(".$var."[".$idx."])=".$val."";
} //DEBUG
return $val;
}
//var is no key name: if action 'add' return empty, otherwise full var string
if(isset($tg['foxaction']) && $tg['foxaction']=='add') $fullvar = '';
return $fullvar;
} //}}}
## get arguments from POST or GET
function FoxRequestArgs ($fx = NULL) {
if (is_null($fx)) $fx = array_merge($_GET, $_POST);
foreach ($fx as $key=>$val) {
if(is_array($val))
foreach($val as $k=>$v) {
$fx[$key][$k] = str_replace("\r",'',stripmagic($v));
}
else $fx[$key] = str_replace("\r",'',stripmagic($val));
}
return $fx;
} //}}}
## call external filter functions
SDV($FoxFilterFunctions, array());
function FoxFilter($pagename, &$fx) {
global $FoxDebug; if($FoxDebug) echo " FoxFilter> "; //DEBUG//
global $FoxFilterFunctions;
//get filter keynames
$fx['foxfilter'] = preg_split("/[\s,|]+/", $fx['foxfilter'], -1, PREG_SPLIT_NO_EMPTY);
foreach($fx['foxfilter'] as $f) {
if (array_key_exists($f,$FoxFilterFunctions)) {
$ffn = $FoxFilterFunctions[$f];
// use specific filter
if(is_callable($ffn, false, $callable_name)) {
$fx = $callable_name($pagename, $fx);
if(!$fx) Redirect($pagename); // Filter is telling us to abort;
}
}
}
} //}}}
## create NAME fields from ptv_NAME fields and add NAME to ptvfields array
function FoxPTVFields($pagename, &$fx) {
global $FoxDebug, $FoxPTVArraySeparator;
if($FoxDebug) echo "
FoxPTVFields>
"; //DEBUG//
//strip ptv_ and make name fields
if(isset($fx['ptvfields']))
$fx['ptvfields'] = explode(",",$fx['ptvfields']);
foreach($fx as $n => $v) {
if(substr($n,0,4)=="ptv_") {
$n = substr($n,4);
$fx[$n] = $v;
$fx['ptvfields'][] = $n;
}
}
if(isset($fx['ptvfields']) && is_array($fx['ptvfields']))
$fx['ptvfields'] = array_unique($fx['ptvfields']);
//flatten input values as arrays for ptvs
if (is_array(@$fx['ptvfields'])) {
foreach($fx['ptvfields'] as $n) {
if (is_array($fx[$n])) { if($FoxDebug) echo "[".$n."] => ";
foreach($fx[$n] as $k => $v) {
if(preg_match('/[\s\']/',$v)) $fx[$n][$k] = '"'.$v.'"'; //doublequote text with spaces or single quotes
}
$fx[$n] = implode($FoxPTVArraySeparator, $fx[$n]); //array input gets converted to text
if($FoxDebug) echo $fx[$n]."";
}
}
}
} //}}}
## add & update page text variables
function FoxPTVAddUpdate($pagename, $text, $fx, $tg ) {
global $PageTextVarPatterns, $EnablePostDirectives, $FoxPTVArraySeparator,
$FoxDebug, $FoxClearPTVFmt, $EnableFoxPTVDelete, $FoxPTVDeleteKey, $FoxMsgFmt;
if ($FoxDebug) echo " FoxPTVAddUpdate>"; //DEBUG//
//PTVs to check
if ($tg['ptvfields']) {
$ptvs = (is_array($tg['ptvfields'])) ? $tg['ptvfields'] : explode(',', $tg['ptvfields']);
foreach ($ptvs as $n) $update[$n] = $fx[$n]; //use ptvfields list to check for PTVs
} else $update = $fx; //use all fields to check for PTVs
$ptvclear = (isset($tg['ptvclear'])) ? explode(",", $tg['ptvclear']) : array(); //array of input fields which will clear PTVs if empty
$pageptvs = array(); //to build array of PTV names in page
//look through PTV patterns and replace matches
foreach ($PageTextVarPatterns as $pat) {
if (!preg_match_all($pat, $text, $match, PREG_SET_ORDER)) continue;
foreach ($match as $m) //$m[0]=all, $m[1]=beforevalue, $m[2]=name, $m[3]=value, $m[4]=aftervalue
{
$k = $pageptvs[] = $m[2];
if (!array_key_exists($k, $update)) continue;
$v = (isset($update[$k])) ? $update[$k] : ''; //new value
if ($m[3]==$v) continue; //no change on this PTV
if ($v=='' && !($ptvclear[0]==1 || in_array($k, $ptvclear))) continue; //empty input gets ignored, unless ptvclear is set to 1 or to ptv field names
if ($v==$FoxClearPTVFmt) $v = ''; // 'NULL' or other special string clears ptv
if (is_array($v)) $v = implode($FoxPTVArraySeparator, $v); //array input gets converted to text
if ($EnablePostDirectives==false) $v = FoxDefuseItem($v);//prevent posting of directives & markup expressions
if ($FoxDebug>4) echo " ".$k."=>".$v."
"; //new ptv name=value
if (!preg_match('/s[eimu]*$/', $pat)) $v = str_replace("\n", ' ', $v); //for any inline pattern replace newlines with spaces
if (strstr($m[4],'[[#')) { $v = trim($v); $m[4] = "\n".$m[4];} //preserve linebreak before ending anchor
if ($EnableFoxPTVDelete==1 && $v==$FoxPTVDeleteKey) $text = str_replace($m[0], '', $text);//erasing ptv
else $text = str_replace($m[0], $m[1].$v.$m[4], $text); //update ptv in text
$GLOBALS['PCache'][$tg['target']]['=p_'.$k] = $v; //update ptv in $PCache
}
}
//add any new ptvs named in ptvfields and do not exist in ptvtarget page
if ($ptvs) {
$ptvfmt = isset($tg['ptvfmt']) ? $tg['ptvfmt'] : 'hidden';
$newptvs = array_diff($ptvs, $pageptvs );
foreach ($newptvs as $k) {
$v = $update[$k];
if (is_array($v)) $v = implode($FoxPTVArraySeparator,$v);
switch ($ptvfmt) {
case 'text' : $text = $text."\n$k: $v\n"; break; //add as text: val
case 'deflist' : $text = $text."\n: $k : $v\n"; break; //add as definition list
case 'section' : $text = $text."\n[[#".$k."]]\n$v\n[[#".$k."end]]\n"; break; //add as anchor section
case 'extra' : $text = $text."\n(::$k:\n$v\n::)\n"; break; //add as extra hidden PTV
case 'hidden' : $text = $text."\n(:$k: $v:)\n"; break; //add as hidden PTV
default : $FoxMsgFmt[] = "$[Error: cannot recognise PTV format] $ptvfmt";
}
$GLOBALS['PCache'][$tg['target']]['=p_'.$k] = $v; //add ptv to $PCache
}
}
return $text;
} //}}}
## check page posting permissions
function FoxPagePermission($pagename, $act, $tn, $fx) {
global $FoxDebug; if($FoxDebug) echo "
FoxPagePermission for $act> $tn
";
global $FoxMsgFmt, $FoxConfigPageFmt, $FoxPagePermissions;
if ($act=='display') return true; //display is allowed
if (!$act) { $FoxMsgFmt[] = "ERROR ($tn): Unknown action: $act . Cannot proceed!"; return;}
// get name patterns from FoxConfig page
$Name = PageVar($pagename, '$Name');
$Group = PageVar($pagename, '$Group');
$config = FmtPageName($FoxConfigPageFmt, $pagename);
if (PageExists($config)) {
$cfpage = ReadPage($config, READPAGE_CURRENT);
if ($cfpage) {
$text = $cfpage['text'];
if(preg_match_all("/^\\s*([\\*\\w][^\\s:]*):\\s*(.*)/m", $text, $matches, PREG_SET_ORDER))
foreach($matches as $m)
$FoxPagePermissions[$m[1]] = $m[2];
}
}
//show($FoxPagePermissions, 'PagePermissions');
// name check for $act against $FoxPagePermissions
$pnames = array();
if(is_array($FoxPagePermissions))
foreach($FoxPagePermissions as $n => $t) {
if(strstr($t,'-'.$act)||strstr($t,'none')) { $pnames[$n]='-'.$n; continue; }
if(strstr($t,$act)||strstr($t,'all')) $pnames[$n]=$n;
}
$pnames = FmtPageName(implode(',',$pnames),$pagename);
//if no permitted names exclude all pages
if($pnames=='') $pnames = '-*.*';
$px = MatchPageNames($tn,$pnames);
$namecheck = (boolean)MatchPageNames($tn,$pnames);
// string check against string patterns
$strcheck = 0;
if(PageExists($tn)) {
$page = ReadPage($tn, READPAGE_CURRENT);
$strcheck = (boolean)( preg_match("/\\(:fox(prepend|append|allow)/", $page['text']) //allow on page which got special markup
OR preg_match("/\\(:fox ".$fx['foxname']." /", $page['text']) ); //allow on page which got the form
}
if($namecheck==0 && $strcheck==0) {
//if ($FoxDebug) echo "Permission denied to $act on $tn ";
$FoxMsgFmt[] = "PERMISSION DENIED to $act on $tn!";
return false;
}
else return true;
} //}}}
## check access code, captcha, new page exists, and required fields
## this runs before individual page processing
function FoxSecurityCheck($pagename, $targets, &$fx) {
global $FoxDebug; if($FoxDebug) echo "
FoxSecurityCheck>
";
global $FoxNameFmt, $FoxMsgFmt, $EnableAccessCode, $EnablePostCaptchaRequired, $EnablePost;
//if preview
if (isset($fx['preview'])) return '';
//if enabled check for access code match
if($EnableAccessCode AND (!(isset($fx['access'])&&($fx['access']==$fx['accesscode'])))) {
FoxAbort($pagename, "$[Error: Missing or wrong Access Code!]");
}
//if enabled check for Captcha code (captcha.php is required)
if($EnablePostCaptchaRequired AND !IsCaptcha()) {
FoxAbort($pagename, "$[Error: Missing or wrong Captcha Code!]");
}
//check pagecheck: if pagecheck page names exists already
if(isset($fx['pagecheck'])) {
$check = explode(',',$fx['pagecheck']);
$stop = 0;
// pagecheck=1 checks all target pages
if($check[0]==1) $check = $targets;
foreach ($check as $pt) {
$page = MakePageName($pagename, $pt);
if($pagename==$page) { $FoxMsgFmt[] = "$[Error: You are not allowed to post to this page!]"; $stop=1; continue;}
if(PageExists($page) AND in_array($page, $targets)) {
$FoxMsgFmt[] = "$[Page] [[$pt]] $[exists already. Please choose another page name!]"; $stop=1; continue;}
}
if ($stop==1) FoxAbort($pagename,"");
}
//check for 'post' and 'cancel' from submit button
if ( !isset($fx['post']) AND !isset($fx['postdraft']) AND !isset($fx['cancel']) AND !isset($fx['preview']) ) {
FoxAbort($pagename, "$[Error: No text or missing post!]");
}
} //}}}
## defuse posting of directives (:...:) and expressions {(...)} by rendering as code
## check only relevant input fields
function FoxDefuseMarkup($pagename, &$fx ) {
global $EnablePostDirectives, $FoxFxSafeKeys;
$fx_check = $fx;
unset($fx_check['foxtemplate']);
foreach ($fx_check as $val) {
foreach ($FoxFxSafeKeys as $key) {
if (array_key_exists($key, $fx_check)) {
unset($fx_check[$key]);
}
}
}
array_walk_recursive( $fx_check, 'FoxDefuseItem' );
$fx = array_merge($fx, $fx_check);
} //}}}
## defuse by rendering as code any markup directives and markup expressions
function FoxDefuseItem( &$item ) {
global $FoxDebug; if($FoxDebug>2) echo " DEFUSE> $item"; //DEBUG//
if (is_array($item)) return $item;
if (!preg_match("/\\(:|\\{\\(/", $item)) return $item;
// render {(..)} and (:...:) as code by using HTML character codes
$item = preg_replace("/\\{(\\(\\w+\\b.*?\\))\\}/", "{$1}", $item);
$item = str_replace("(:", "(:", $item);
$item = str_replace(":)", ":)", $item);
//undo for markup directives wrapped in [@...@] or [=...=]
if (preg_match_all("/(\\[[@|=])[^\\]]*(\\(:)(.*?[@|=]\\])/s", $item, $mp)) {
foreach($mp[0] as $i => $v) {
$v = str_replace("(:","(:",$v);
$v = str_replace(":)",":)",$v);
$item = str_replace( $mp[0][$i], $v, $item);
}
}
//undo for markup expressions wrapped in [@...@] or [=...=]
if (preg_match_all("/(\\[[@|=])[^\\]]*({\\(.*?\\)})(.*?[@|=]\\])/s", $item, $mp)) {
foreach($mp[0] as $i => $v) {
$v = str_replace("{(","{(",$v);
$v = str_replace(")}",")}",$v);
$item = str_replace( $mp[0][$i], $v, $item);
}
}
} //}}}
## make a WikiWord out of a string
function FoxWikiWord($str) {
global $FoxDebug; if($FoxDebug) echo " FoxWikiWord> "; //DEBUG//
global $MakePageNamePatterns;
$str = preg_replace('/[#?].*$/', '', $str);
$nm = $str;
foreach($MakePageNamePatterns as $pat => $rep) {
if(is_callable($rep) && $rep != '_') $nm = preg_replace_callback($pat,$rep,$nm);
else $nm = preg_replace($pat,$rep,$nm);
}
return $nm;
} //}}}
## newedit opens page in the edit form, it can only run as last page process
function FoxNewEdit($pagename, $template, $fx, $tg) {
global $FoxDebug; if($FoxDebug) echo " FoxNewEdit> "; //DEBUG//
if(PageExists($tg['target'])) Redirect($tg['target']); //jump to existing page
$urlfmt = '$PageUrl?action=edit';
if ($template) {
//merging fields and template, put into Session var for use with ?action=edit&foxtemptext=1
@session_start();
$_SESSION["FoxTempPageText"] = $template;
//add special template marker before redirecting to edit
$urlfmt.= '&foxtemptext=1';
}
if ($fx['redir']!==1)
Redirect($tg['target'], $urlfmt); // open new page to edit
} //}}}
## upload files
function FoxPostUpload($pagename, $fx, $auth='upload') {
global $FoxDebug; if ($FoxDebug) echo " FoxPostUpload>";
global $UploadVerifyFunction, $UploadDir, $UploadPrefix, $UploadPrefixFmt,
$LastModFile, $EnableUploadVersions, $Now, $FoxMsgFmt, $FmtV;
$uptarget = $fx['uptarget'];
if (function_exists('MakeUploadPrefix'))
$upprefix = MakeUploadPrefix($uptarget);
else $upprefix = FmtPageName("$UploadPrefixFmt", $uptarget);
$dirpath = $UploadDir.$upprefix;
$page = RetrieveAuthPage($uptarget, $auth, true, READPAGE_CURRENT);
if (!$page) FoxAbort($pagename, "?cannot upload to $uptarget");
foreach($_FILES as $n => $upfile) {
$upname = $upfile['name'];
if ($upname=='') continue;
// check for new upload filename
if ($fx[$n.'_name']) $upname = $fx[$n.'_name'];
$upname = MakeUploadName($uptarget, $upname);
if (!function_exists($UploadVerifyFunction))
FoxAbort($pagename, '?no UploadVerifyFunction available');
$filepath = $dirpath.'/'.$upname;
$result = $UploadVerifyFunction($uptarget, $upfile, $filepath);
if ($result=='') {
$filedir = preg_replace('#/[^/]*$#','',$filepath);
mkdirp($filedir);
if (IsEnabled($EnableUploadVersions, 0))
@rename($filepath, "$filepath, $Now");
if (!move_uploaded_file($upfile['tmp_name'], $filepath))
{ FoxAbort($pagename, "?cannot move uploaded file to $filepath"); return; }
fixperms($filepath, 0444);
if ($LastModFile) { touch($LastModFile); fixperms($LastModFile); }
$result = "upresult=success";
}
# process results for message
$re = explode('&',substr($result,9));
# special cases:
if($re[0]=='badtype' OR $re[0]=='toobigext') {
global $upext, $upmax;
$r1 = explode('=',$re[1]);
$upext = $r1[1];
$r2 = explode('=',$re[2]);
$upmax = $r2[1];
}
$result = $re[0];
$FoxMsgFmt[] = "$[UL$result] $upname";
}
} //}}}
# last
function FoxFinish($pagename, $fx, $msg) {
StopWatch('FoxFinish start');
global $InputValues, $FoxMsgFmt;
// wipe out input values, so there's no redisplay
if (isset($fx['keepinput'])) { //keep values for selected input fields
$keep = explode(',', $fx['keepinput']);
if ($fx['keepinput']!=1) {
foreach($InputValues as $i => $v) {
if (in_array($i, $keep)) continue;
unset($GLOBALS['InputValues'][$i]);
}
}
} else //wipe all
foreach($InputValues as $i => $v)
unset($GLOBALS['InputValues'][$i]);
HandleDispatch($pagename,'browse',$msg);
exit;
} //}}}
## abort by displaying error message and returning to page
function FoxAbort($pagename, $msg) {
global $InputValues, $FoxMsgFmt, $MessagesFmt;
$FoxMsgFmt[] = $msg;
$MessagesFmt[] = ""; //legacy using (:messages:) markup
HandleDispatch($pagename,'browse');
exit;
} //}}}
# FoxTimer aborts if $FoxProcessTimeMax is exceeded, returns process time,
# sets entries in $StopWatch array, displayed with config settings:
# $EnableDiag = 1;
# $HTMLFooterFmt['stopwatch'] = 'function:StopWatchHTML 1'; //function is in scripts/diag.php
function FoxTimer($pagename, $x) {
global $FoxProcessTimeMax, $StopWatch;
static $wstart = 0;
$wtime = strtok(microtime(), ' ') + strtok('');
if (!$wstart) $wstart = $wtime;
$wtime = $wtime-$wstart;
$StopWatch[] = sprintf("%04.2f %s", $wtime, $x);
$xtime = sprintf("%04.2f %s", $wtime, '');
if($xtime>$FoxProcessTimeMax)
FoxAbort($pagename, "$[Error: processing stopped before maximum script timeout.] $[Page process:] $xtime sec");
return $xtime;
} //}}}
## validation check for form input as set by (:foxcheck ... :) markup
function FoxInputCheck($pagename, $fx) {
global $FoxDebug; if($FoxDebug) echo " FoxInputCheck> "; //DEBUG//
global $FoxCheckError, $FoxCheckErrorMsg, $FoxMsgFmt, $FoxClearPTVFmt;
if (isset($fx['cancel'])) return '';
$check = array();
foreach($fx as $k => $ar) {
if (substr($k,0,4)!='chk_') continue;
if (!is_array($ar)) continue;
foreach($ar as $i => $v) {
$n = substr($k,4); // remove leading 'chk_'
if ($v=='') continue; // set only non-empty values
if ($n=='name') {
$nms = explode(',',$v);
foreach($nms as $j => $nm)
$check[$i]['names'][$j] = $nm;
} else $check[$i][$n] = $v;
}
}
if($FoxDebug>4) show($check,'check');
$FoxCheckError = array();
foreach($check as $i => $opt) {
foreach($opt['names'] as $n) {
if ($opt['empty']==1 && ($fx[$n]=='' || $fx[$n]==$FoxClearPTVFmt)) continue;
if (!isset($opt['match'])) $opt['match'] = "?*";
$pat = (isset($opt['regex'])) ? $opt['regex'] : ".+";
list($inclp, $exclp) = GlobToPCRE($opt['match']);
if ( $inclp && !preg_match("/$inclp/is", $fx[$n])
|| $exclp && preg_match("/$exclp/is", $fx[$n])
|| !preg_match("/$pat/is", $fx[$n])) {
$FoxMsgFmt[$n] = isset($opt['msg']) ? $opt['msg']
: "$[Invalid parameter:] $n";
$FoxCheckError[] = $n;
}
if (@$opt['if'] && !CondText($pagename, 'if '.$opt['if'], 'yes')) {
$FoxMsgFmt[$n] = isset($opt['msg']) ? $opt['msg']
: "$[Input condition failed]";
$FoxCheckError[] = $n;
}
}
}
$errmsg = (isset($fx['foxcheckmsg'])) ? $fx['foxcheckmsg'] : $FoxCheckErrorMsg;
//avoid abort or call to foxedit when preview
if (isset($fx['preview'])) unset($FoxCheckError);
if ($FoxCheckError) {
if ($_SESSION['foxedit'][$pagename]) FoxHandleEdit($pagename);
else FoxAbort($pagename, $errmsg);
}
} //}}}
## build javascript for simple validation that required fields have values
function FoxJSFormCheck($formcheck) {
$reqfields = preg_split("/[\s,|]+/", $formcheck, -1, PREG_SPLIT_NO_EMPTY);
$out = "
";
return $out;
} //}}}
## provide {$AccessCode} page variable:
$FmtPV['$AccessCode'] = rand(100, 999);
## add page variable {$FoxPostCount}, counts message items per page
$FmtPV['$FoxPostCount'] = 'FoxStringCount($pn,"#foxbegin")';
function FoxStringCount($pagename,$find) {
$page = ReadPage($pagename, READPAGE_CURRENT);
$n = substr_count($page['text'], $find);
// if ($n==0) return ''; #suppressing 0
return $n;
}
## use like (:input default $:MyPTV[] {(foxfixptv $:MyPTV)} :)
## for fixing CSV PTV data to space separated data for use in (:input default ...:)
$MarkupExpr['foxfixptv'] = 'FoxFixPTV($pagename, $args[0])';
function FoxFixPTV($pn, $ptv) {
$p = PageTextVar($pn, substr($ptv,2));
preg_match_all('/(\\"[^\\"]+\\")|[^,\\s]+/',$p,$m);
$a = $m[0];
if(!is_array($a)) return '';
foreach($a as $k => $v) $a[$k] = PHSC(trim($v,', '),ENT_NOQUOTES);
return implode(" ",$a);
}
## helper function for php 4 which has no array_walk_recursive function
if (!function_exists('array_walk_recursive')) {
function array_walk_recursive(&$input, $funcname, $userdata = "") {
if (!is_callable($funcname) || !is_array($input)) return false;
foreach ($input as $key => $value) {
if (is_array($input[$key]))
array_walk_recursive($input[$key], $funcname, $userdata);
else {
$saved_value = $value;
if (!empty($userdata)) $funcname($value, $key, $userdata);
else $funcname($value, $key);
if ($value != $saved_value) $input[$key] = $value;
}
}
return true;
}
} //}}}
## decode htmlspecialchars
function Fox_htmlspecialchars_decode($str, $style=ENT_COMPAT) {
if ($style === ENT_COMPAT) $str = str_replace('"','\"',$str);
if ($style === ENT_QUOTES) $str = str_replace(''','\'',$str);
$str = str_replace('<','<',$str);
$str = str_replace('>','>',$str);
$str = str_replace('&','&',$str);
return $str;
}
# debug helper function to echo preformatted array with optional label
if (!function_exists('show')) {
function show($arr,$lbl=''){echo "
$lbl ";print_r($arr);echo "
";}
} //}}}
///EOF