$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']) ? $GLOBALS['FoxJSFormCheckFunction']($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, csv, ptv, copy: load page file for saving if ($act=='add' || $act=='replace' || $act=='csv' || $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."
FoxAddText>"; //DEBUG// //get array with mark & form positions $ms = FoxSetMarks($pn, $text, $fx, $tg); $mark = (isset($ms[0]['mark']) ? $ms[0]['mark'] : ''); $pre = $aft = ''; $err=0; //calculate section position and length switch ($ms['put']) { case '#top' : //legacy, next case 'top' : $pos = 0; $aft = "\n"; break; case '#bottom' : //legacy, next case 'bottom': $pos = strlen($text); $pre = "\n"; break; case 'above' : if (!isset($ms['Mpos'])) { $FoxMsgFmt[] = "$[Error: Found no mark to add above!]"; return $text; } else { $pos = $ms['Mpos']; $aft = "\n"; break; } case 'below' : if (!isset($ms['Mpos'])) { $FoxMsgFmt[] = "$[Error: Found no mark to add below!]"; return $text; } else { $pos = $ms['Mpos'] + $ms['Mlen']; $pre = "\n"; break; } case '#append' : //legacy, next case 'aboveform': if (!isset($ms['Fpos'])) { $FoxMsgFmt[] = "$[Error: Found no form to add above!]"; return $text; } else { $pos = $ms['Fpos']; $aft = "\n"; break; } case '#prepend' : //legacy, next case 'belowform': if (!isset($ms['Fpos'])) { $FoxMsgFmt[] = "$[Error: Found no form to add below!]"; return $text; } else { $pos = $ms['Fpos'] + $ms['Flen']; $pre = "\n"; break; } case 'insert' : if (!isset($ms['Mpos'])) { $FoxMsgFmt[] = "$[Error: Found no mark to insert after!]"; return $text; } else { $pos = $ms['Mpos'] + $ms['Mlen']; break; } case 'insertbefore' : if (!isset($ms['Mpos'])) { $FoxMsgFmt[] = "$[Error: Found no mark to insert before!]"; return $text; } else { $pos = $ms['Mpos']; break; } default: $FoxMsgFmt[] = "$[Error:] '{$ms['put']}' $[is not a valid option with 'add'!] "; return $text; } //DEBUG// if($FoxDebug>4) echo "
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, but for csv editing we need to preserve \n , '\' is linebreak token in csv, not '\n' if (!isset($fx['csvact'])) $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; } $result = implode("\n",$result); if($FoxDebug>6) 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>6) 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>7) { if(is_null($idx)) echo "
".$str."
VALUE(".$var.")="; else echo "VALUE(".$var."[".$index."])=";}//DEBUG// $fti = 'none'; if (isset($tg['t_count']) && $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']>7) { 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' || $tg['foxaction']=='csv')) $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['post2']) AND !isset($fx['post_x']) 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 (empty($fx['redir'])) 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 (isset($opt['empty']) && $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); } ## 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 "";} } //}}} if (!function_exists('vdu')) { function vdu($arr,$lbl=''){echo "$lbl";var_dump($arr);echo "";} } //}}} ///EOF