<?php if (!defined('PmWiki')) exit();

## DESCRIPTION:  The ZAPlite recipe extends forms capability on PmWiki, by adding a powerful forms processing engine, plus several useful markups. For info, see docs at http://www.pmwiki.org/wiki/Cookbook/ZAPdata, or visit the ZAP demo site at WWW.ZAPSITE.ORG.  Author: Dan Vis aka Caveman <editor àt fast döt st>, Copyright 2006.  License http://www.gnu.org/licenses/gpl.html GNU General Public License

SDV($ZAPauth[login], "read");
SDV($ZAPauth[forms], "zap");
$PageAttributes['passwdzap'] = 'Set ZAP forms password: ';
$DefaultPasswords['zap'] = 'id:*';
SDV($ZAPcode, "NOCODE");
SDV($ZAPprofiles, "Profiles");

$HandleActions['zap'] = 'ZAPengine';
function ZAPengine($ZAPflag = 0) {
	global $WorkDir, $WikiDir, $pagename, $ScriptUrl, $MessagesFmt, $m, $ZAPauth, $ZAPtime, $ZAPprofiles;
	$lock = ZAPsecure();
	$m = "Form submitted. ";  // holds system messages.
	$ZAPtime = time();

	foreach ($_POST as $field => $value) {
			if (get_magic_quotes_gpc()) $_POST[$field] = stripslashes($value);  //stripslashes
			$_POST[$field] = preg_replace('/\\(:/', '(&#x3a;', $value);  //protect
			$_POST[$field] = preg_replace('/\\{(\\w+)\\}/e', "\$_POST[$1]", $value);  //replace fields
			if (is_array($value)) $_POST[$field] = implode(",", $value);  //lists to csv
			}
	if (!isset($_POST[nextpage])) $_POST[nextpage] = $pagename;
	if (!isset($_POST[datapage])) $_POST[datapage] = $pagename;

	foreach ($_POST as $field => $value) {
	
	if(CondAuth($pagename, $ZAPauth[login])) {

		if ($field == "login") {
			$p = "$ZAPprofiles.$_POST[Member]";
			if (($value == "auto") and (! PageExists($p))) {
				AuthUserId($pagename, $_POST['Member']);
				$m .= "You have been successfully logged in. ";					
				}
			else {
				$pass1 = ZAPgetdata("Password","$ZAPprofiles.$_POST[Member]");
				$pass2 = $_POST['Password'];
				if (($pass1 == $pass2) && ($pass1 != "")) {			   
					AuthUserId($pagename, $_POST['Member']);
					$m .= "You have been successfully logged in. ";
					}
				else ZAPwarning("Incorrect member name or password.");
				}
			continue;
			}

		if ($field == "required") {
			$r = explode(",", $value);
			foreach ($r as $v) {
				switch ($v) {
					case "newmember" :
						if ($_POST[$v] == "") ZAPwarning("Please enter a member name.");
						if (PageExists("$ZAPprofiles.$_POST[$v]")) ZAPwarning("Member name already taken.  Please try again.");
						if ($_POST[$v] != PageVar(MakePageName($pagename, $_POST[$v]), '$Name')) ZAPwarning("Invalid member name. Please try again.");
						break;
					case "member" :
						if (! PageExists("$ZAPprofiles.$_POST[$v]")) ZAPwarning("Member name does not exist. Please try again.");
						break;
					case "newpage" :
						if (PageExists("$_POST[$v]")) ZAPwarning("Page already exists. Please try again.");
						break;
					case "newgroup" :
						if (PageExists("$_POST[$v].RecentChanges")) ZAPwarning("Group already exists. Please try again.");
						break;
					case "Email" :
						if (! ereg("^.+@.+\..+$", $_POST[$v])) ZAPwarning("Invalid email address entered.");
						break;
					default :
						if ((isset($_POST[$v."pattern"])) && (! ereg($_POST[$v."pattern"], $_POST[$v]))) ZAPwarning("Field \"$v\" has an invalid format. Please try again.");
						if ($_POST[$v] == "") ZAPwarning("Field \"$v\" required. Please try again.");
						break;
					}
				}
			continue;
			}
		} 

	if((CondAuth($pagename, $ZAPauth[forms])) or ((CondAuth($pagename, $ZAPauth[login])) && ($lock != "nolock"))) {
		if (substr($field, -4, 4) == "page") $_POST[$field] = ZAPfixpage($value);
		
		if (substr($field, 0, 4) == "link") $_POST[$field] = "$ScriptUrl?n=$_POST[$field]";
			
		if (substr($field, 0, 5) == "count") {
			if (substr($_POST[$field], 0, 1) == "=") $_POST[$field] = substr($_POST[$field], 1);
			elseif (substr($_POST[$field], 0, 1) == "-") $_POST[$field] = substr($_POST[$field], 1) - 1;
			else $_POST[$field] = $_POST[$field] + 1;
			continue;
			}

		if (substr($field, 0, 6) == "random") {
			$n = explode("|", $value);
			$_POST[$field] = rand($n[0],$n[1]);
			continue;
			}

		if (substr($field, 0, 4) == "time") {
			$t = explode("|", $value);
			if (($t[0] == "+") || ($t[0] == "")) $t[0] = $ZAPtime;
			if (isset($t[1])) $_POST[$field] = strftime($t[1], $t[0]);
			else $_POST[$field] = $t[0];
			continue;
			}

		if (substr($field, 0, 8) == "messages") {
		ZAPwarning($_POST[messages]);
			if (substr($_POST[messages], 0, 1) == "+") $m .= substr($_POST[messages], 1) . " ";
			else $m = $_POST[messages] . " ";
			continue;
			}

		if ($field == passdata) {
			$d = explode(",", $_POST[passdata]);
			foreach ($d as $v) $passdata .= "?$v=$_POST[$v]";
			if ($passdata == "?=") $passdata = "";
			}
			
		if (substr($field, 0, 8) == "savedata") {
			$text = "";
			$data = ZAPsetdata($value);
			ZAPsavepage($_POST[datapage],$text,$data);
			continue;
			}

		if (substr($field, -4, 4) == "list") {
			if ((substr($value, 0, 1) == "+") || (substr($value, 0, 1) == "-")) {
				$list = ZAPgetdata($field, $_POST[datapage]);
				$i = explode(",", $value);
				foreach ($i as $ii) {
					$plusminus = substr($ii, 0, 1);
					$item = substr($ii, 1);
					switch($plusminus) {
						case "-" :
							$list = ereg_replace("$item,", '', $list);
							$list = ereg_replace(",$item", '', $list);
							break;
						case "+" :
							$list = $list . "," . $item;
							break;
						}
					}
				$_POST[$field] = $list;
				}
			if (isset($_POST[substr($field, 0, -4) . "fmt"])) {
				$x = explode("^", $_POST[substr($field, 0, -4) . "fmt"]);
				$l = explode(",", $_POST[$field]);
				foreach($l as $ll) $xx .= str_replace("ITEM", $ll, "$x[0]$x[1]");
				$xx = substr($xx, 0, 0 - strlen("$x[1]"));
				$_POST[substr($field, 0, -4)] = $xx;
				}
			}
			
		if (($field == "banlist") || ($field == "approvelist")) {
			$p = explode(",", $value);
			$match = false;
			foreach ($p as $pp) if ($pp == $GLOBALS[AuthId]) $match = true;
			if (($field == "banlist") && ($match == true)) ZAPwarning("You are not authorized to use this form. ");
			if (($field == "provelist") && ($match != true)) ZAPwarning("You are not authorized to use this form. ");
			continue;
			}
		} 

	}
	if ($ZAPflag != 0) return;
	if (($_POST[nextpage] == $pagename) && (! isset($passdata))) {
		$MessagesFmt[] = "<h5 class='wikimessage'>$[$m]</h5>";
		HandleBrowse($pagename);
		}
	else Redirect(FmtPageName($_POST[nextpage] . $passdata, $pagename));
	}

function ZAPwarning($m) {
	global $pagename, $MessagesFmt;
	$MessagesFmt[] = "<h5 class='wikimessage'>$[$m]</h5>";
	HandleBrowse($pagename);
	die();
	}

function ZAPsavepage($mypage, $mytext, $mydata) {
	global $WorkDir, $_POST, $m;
	$oldpage = ReadPage($mypage);
	if ($mytext == "") {
		$oldtext = $oldpage['text'];
		if (strpos($oldtext, '(:comment data:)')) $mytext = substr($oldtext, 0, strpos($oldtext, '(:comment data:)'));
		else $mytext = $oldtext . " \n\n";
		}
	$newpage = $oldpage;
	$newpage['text'] = $mytext . "(:comment data:)\n\n" . $mydata;
	UpdatePage($mypage, $oldpage, $newpage);
	if ($mydata != "") $m .= "Data has been successfully saved. ";
	return;
	}

function ZAPsetdata($fields) {
	global $m, $_POST;
	$pagedata = "";
	$hidedata = "";
	$hide = false;
	$urlin = array('%0D%0A', '%5C%5C');
	$urlout = array('%5B%5B%3C%3C%5D%5D%0A', '%5c%5c%5c');
	$htmlin = array("'",'  ');
	$htmlout = array('&apos;','&nbsp;&nbsp;');
	$d = explode(",", $fields);
	foreach ($d as $f) {
		$v = urldecode(str_replace($urlin, $urlout, urlencode($_POST[$f])));
		$v = str_replace($htmlin, $htmlout, $v);
		if (substr($f, 0, 4) == hide) {
			$hidedata .= substr($f, 4) . '="' . $v . '"' . "\n\n";
			$hide = true;
			}
		else $pagedata .= "(:$f: $v:)\n\n"; 
		}
	if ($hide == true) $pagedata = $pagedata . "(:if false:)\n\n$hidedata(:if:)";
	return $pagedata;
	}

function ZAPgetdata($f,$p) {
	$l = ReadPage($p);
	$ll = explode("(:comment data:)", $l['text']);
	$field = explode("\n\n", $ll[1]);
	foreach ($field as $value) {
		if (substr($value, 0, 4) == "(:if") continue;
		if (substr($value, 0, 2) == "(:") {
			$value = substr($value, 2, -2);
			$a = ': ';
			}
		else $a = '="';
		$v[0] = substr($value, 0, strpos($value, $a));
		$v[1] = substr($value, strpos($value, $a) + 2);
		if ($a == '="') $v[1] = substr($v[1],0,-1);
		if ($v[0] == $f) return $v[1];
		}
	return;
	}

function ZAPfixpage($v) {
	global $pagename, $ZAPtime, $_GET, $_POST, $m;
	if ($v == "") return $pagename;
	if (!strpos($v, ".")) {
		if (isset($_POST[basegroup])) $v = "$_POST[basegroup].$v";
		else $v = substr($pagename, 0, strpos($pagename, ".")) . ".$v";
		}
	$vv = explode(".", $v);
	if (strpos($vv[1], "?")) {
		$vv[2] = substr($vv[1], strpos($vv[1], "?"));
		$vv[1] = substr($vv[1], 0, strpos($vv[1], "?"));
		}
    if (substr($vv[1], 0, 4) == "GET:") $vv[1] = $_GET[substr($vv[1], 4)];
	$pn = explode(".", $pagename);
	$r1 = array('*','^'); 
	$r2 = array("$pn[0]","$pn[1]");
	$vv[0] = str_replace($r1, $r2, $vv[0]);
	if (isset($ZAPtime)) $t = $ZAPtime;
	else $t = time();
	$e = 1000;
	$ee = 1000;
	if (strpos("$vv[0]$vv[1]", "#") || strpos("$vv[0]$vv[1]", "=")) {
		$g = $vv[0];
        foreach(ListPages("/^$g\\.\\d/") as $n) {
			$n = substr($n,strlen($g)+1);
			$e = max($e,$n);
			}
		if ((PageExists("$vv[0].$e")) && (strpos("$vv[0]$vv[1]", "#"))) $ee = $e + 1;
		}
	$rr1 = array('*','^','@','=','#','+','~'); 
	$rr2 = array("$pn[1]","$pn[0]","$GLOBALS[AuthId]","$e","$ee","$ZAPtime","Profiles");
	$v = str_replace($rr1, $rr2, "$vv[0].$vv[1]") . $vv[2];
	return "$v";
	}

function ZAPsecure() {
	global $_POST, $pagename, $ZAPcode;
	if (($ZAPcode != "NOCODE") && ($ZAPcode != $_POST[zapcode])) ZAPwarning("This form requires a passcode.");
	session_start();
	if (! isset($_SESSION[ZAPlock]["$pagename-$GLOBALS[AuthId]-$_POST[ZAPkey]"])) ZAPwarning("An error occurred. Form could not be processed.");
	$lockpattern = $_SESSION[ZAPlock]["$pagename-$GLOBALS[AuthId]-$_POST[ZAPkey]"];
	unset($_SESSION[ZAPlock]);
	if ($lockpattern != "nolock") {
		$f = explode("`", $lockpattern);
		foreach($f as $ff) {
			if (strpos($ff, '=')) $lock[substr($ff, 0, strpos($ff, '='))] = substr($ff, strpos($ff, '=') + 1);
			else $lock[$ff] = "";
			}
		foreach ($_POST as $field => $value) {
			if (! isset($lock[$field]))	unset($_POST[$field]);
			if ($lock[$field] != "") $_POST[$field] = $lock[$field];
			}
		}
	return $lockpattern;
	}

Markup('zapform', '<{$var}', '/\(:zapform(.*?):\)/ei', "ZAPform('$1')");
Markup('zapend', 'inline', '/\(:zapend:\\)/', '</form>');
Markup('zapdata', '<{$var}', '/\(:zapdata(.*?):\)/ei', "ZAPdata('$1')");
Markup('zapget', '<{$var}', '/\(:zapget(.*?):\)/ei', "ZAPget('$1')");
Markup('zapkeep', '>{$var}', '/\\(:keep (.*?):\\)/esi', "Keep(ZAPkeep(PSS('$1')))");

function ZAPform($d) {
	global $pagename;
	if (strpos($d, "`")) $d = substr($d, strpos($d, ' `') + 2, strpos($d, '` ') - 2);
	else $d = "nolock";
	$x = rand(10000,99999);
	session_start();
	$_SESSION[ZAPlock]["$pagename-$GLOBALS[AuthId]-$x"] = $d;
	return "(:input form:)\n(:input hidden action zap:)\n(:input hidden ZAPkey $x:)\n";
	}

function ZAPdata($d) {
	global $WorkDir, $FmtPV;
	$d = ZAPfixpage(substr($d, 1));
	$FmtPV['$thread'] = "'" . substr($d, strpos($d, ".")+1) . "'";
	if (PageExists($d)) {
		$page = ReadPage($d);
		$contents = $page[text];
		$d = substr($contents, strpos($contents, "(:comment data:)") + 16);
		$field = explode("\n\n", $d);
		foreach ($field as $value) {  
			if (substr($value, 0, 4) == "(:if") continue;
			if (substr($value, 0, 2) == "(:") {
				$value = substr($value, 2, -2);
				$a = ': ';
				}
			else $a = '="';
			$v[0] = substr($value, 0, strpos($value, $a));
			$v[1] = substr($value, strpos($value, $a) + 2);
			if ($a == '="') $v[1] = substr($v[1],0,-1);
			if ($v[0] != "") $FmtPV["$$v[0]"] = "'" . $v[1] . "'";
			}
		return;
		}
	return;
	}

function ZAPget($d) {
	global $WorkDir, $FmtPV, $GET;
	foreach ($_GET as $g => $gg) if ($gg != "") $FmtPV["$$g"] = "'" . $gg . "'";
	return;
	}

function ZAPkeep($x) {
	$out = array("'",'  ','%0D%0A');
	$in = array('%26amp%3Bapos%3B','%26amp%3Bnbsp%3B%26amp%3Bnbsp%3B','%5B%5B%26lt%3B%26lt%3B%5D%5D%0A');
	$x = urldecode(str_replace($in, $out, urlencode($x)));
	return $x;
	}


Markup('select', 'inline', '/\(:select (.*?):\\)/', '<select name=$1>');
Markup('option', 'inline', '/\\(:option (.*?):\\)/e', "Keep(PSS(\"<option value='$1'>\"))");
Markup('selectend', 'inline', '/\(:selectend:\\)/', '</select>');
Markup('textarea', 'inline', '/\\(:textarea (.*?):\\)/e', "Keep(PSS(\"<textarea $1>\"))");
Markup('textareaend', 'inline', '/\(:textareaend:\\)/', '</textarea>');