1<?php
2/**
3 * formular Plugin: Displays Forms
4 *
5 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author     Ole Rienow <wikiform@rienow.eu>
7 *
8 */
9
10/**
11 * Changes Log
12 * [2008-01-09] Original Form Plugin from Ole Rienow
13 * [2008-02-17] Small additions by Stephane Chamberland <stephane.chamberland@gmail.com>
14 * - rename to Formular (not to confuse with Esther's Form plugin) and to keep compatibility with previous versions settings
15 * - make compatible with configuration plugin
16 * - localize [include only the En, Fr translations]
17 * - add default styles [borrowed from Esther's form plugin]
18 * [2008-06-29] You can hand over GET-Parameters as Standard Values for Textfields and Textareas
19 * [2008-07-03]
20 *	- Many Refactorings
21 *	- Constraints are now also possible for self written Scripts
22 *	- Username in Mail
23 *	- Added Grepnot Constraint
24 * [2008-07-09]
25 *	- Added local wikipage Language (e.g. Hidden lang "en";)
26 * [2008-07-17]
27 *  - Added Debug-Modus
28 *  - Bugfix in the Constraint-Writer for self written Scripts
29 * [2008-07-18]
30 *  - Bugfix in MailForm creation
31 *  - Added Feature to hold Data if given Data is not valid
32 * [2008-07-19]
33 *  - Added File-Upload feature
34 * [2008-07-20]
35 *  - Hold Data in Selectboxes, Radiobuttons and Checkboxes as well
36 *  - Bugfix for Multiple Line Data in Textareas
37 * [2008-07-23]
38 *  - Writing Debug-Infos to File
39 * [2009-03-12]
40 *  - little bugfix of missing quotation mark in textareas
41 *  - new italian translation - thanks to Diego Pierotto
42 */
43
44/**$renderer->info['cache'] = false;
45 * Configuration specified in DOKUPATH/conf/local.php
46 *
47 * $conf['plugin']['formular']['AllowInclude'] = 1|0;
48 * $conf['plugin']['formular']['mailPath'] = "data/formplugin/";
49 * $conf['plugin']['formular']['selectPage'] = "formplugin:select";
50 * $conf['plugin']['formular']['mailSubject'] = "Message -- formular plugin";
51 * $conf['plugin']['formular']['mailFrom'] = "";
52 *
53 */
54
55if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
56if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
57require_once(DOKU_PLUGIN.'syntax.php');
58
59/**
60 * All DokuWiki plugins to extend the parser/rendering mechanism
61 * need to inherit from this class
62 */
63class syntax_plugin_formular extends DokuWiki_Syntax_Plugin {
64
65 	var $scriptPath;
66	var $mailPath;
67	var $mailFile;
68	var $internalScript = false;
69	var $localLang = array();
70
71	/**
72	* return some info
73	*/
74	function getInfo(){
75		return array(
76			'author' => 'Ole Rienow',
77			'email'  => 'wikiform@rienow.eu',
78			'date'   => '2009-03-12',
79			'name'   => 'Formular Plugin',
80			'desc'   => 'Creates HTML Forms',
81			'url'    => 'http://wiki.splitbrain.org/plugin:form',
82		);
83	}
84
85	function getType(){
86		return 'substition';
87	}
88
89	/**
90	 * What about paragraphs? (optional)
91	 */
92	function getPType(){
93		return 'block';
94	}
95
96	/**
97	 * Where to sort in?
98	 */
99	function getSort(){
100		return 999;
101	}
102
103	/**
104	 * Connect pattern to lexer
105	 */
106	function connectTo($mode) {
107		$this->Lexer->addEntryPattern('<FORM.*?>(?=.*?</FORM>)',$mode,'plugin_formular');
108	}
109
110	function postConnect() {
111		$this->Lexer->addExitPattern('</FORM>', 'plugin_formular');
112	}
113
114 	function phpParsed($string) {
115		require_once DOKU_INC . 'inc/parser/xhtml.php';
116		require_once DOKU_INC . 'inc/parser/parser.php';
117
118		$Parser = & new Doku_Parser();
119		$Parser->Handler = & new Doku_Handler();
120		$Parser->addMode('php',new Doku_Parser_Mode_PHP());
121
122		$instructions = $Parser->parse($string);		// Get a list of instructions
123		$Renderer = & new Doku_Renderer_XHTML();		// Create a renderer
124
125		// Loop through the instructions
126		foreach ( $instructions as $instruction ) {
127			call_user_func_array(array(&$Renderer, $instruction[0]),$instruction[1]);
128		}
129
130		return trim(substr($Renderer->doc, 4, -5));
131	}
132
133	function parsed($string) {
134		require_once DOKU_INC . 'inc/parser/xhtml.php';
135		require_once DOKU_INC . 'inc/parser/parser.php';
136
137		$Parser = & new Doku_Parser();
138		$Parser->Handler = & new Doku_Handler();
139
140		$Parser->addMode('listblock',new Doku_Parser_Mode_ListBlock());
141		$Parser->addMode('preformatted',new Doku_Parser_Mode_Preformatted());
142		$Parser->addMode('notoc',new Doku_Parser_Mode_NoToc());
143		$Parser->addMode('header',new Doku_Parser_Mode_Header());
144		$Parser->addMode('table',new Doku_Parser_Mode_Table());
145		$Parser->addMode('linebreak',new Doku_Parser_Mode_Linebreak());
146		$Parser->addMode('footnote',new Doku_Parser_Mode_Footnote());
147		$Parser->addMode('hr',new Doku_Parser_Mode_HR());
148		$Parser->addMode('unformatted',new Doku_Parser_Mode_Unformatted());
149		$Parser->addMode('php',new Doku_Parser_Mode_PHP());
150		$Parser->addMode('html',new Doku_Parser_Mode_HTML());
151		$Parser->addMode('code',new Doku_Parser_Mode_Code());
152		$Parser->addMode('file',new Doku_Parser_Mode_File());
153		$Parser->addMode('quote',new Doku_Parser_Mode_Quote());
154		$Parser->addMode('acronym',new Doku_Parser_Mode_Acronym(array_keys(getAcronyms())));
155		$Parser->addMode('multiplyentity',new Doku_Parser_Mode_MultiplyEntity());
156		$Parser->addMode('quotes',new Doku_Parser_Mode_Quotes());
157		$Parser->addMode('camelcaselink',new Doku_Parser_Mode_CamelCaseLink());
158		$Parser->addMode('internallink',new Doku_Parser_Mode_InternalLink());
159		$Parser->addMode('media',new Doku_Parser_Mode_Media());
160		$Parser->addMode('externallink',new Doku_Parser_Mode_ExternalLink());
161		$Parser->addMode('windowssharelink',new Doku_Parser_Mode_WindowsShareLink());
162		$Parser->addMode('filelink',new Doku_Parser_Mode_FileLink());
163		$Parser->addMode('eol',new Doku_Parser_Mode_Eol());
164
165		$formats = array (
166			'strong', 'emphasis', 'underline', 'monospace',
167			'subscript', 'superscript', 'deleted',
168		);
169		foreach ($formats as $format) {
170			$Parser->addMode($format,new Doku_Parser_Mode_Formatting($format));
171		}
172
173		$instructions = $Parser->parse($string);		// Get a list of instructions
174		$Renderer = & new Doku_Renderer_XHTML();		// Create a renderer
175
176		// Loop through the instructions
177		foreach ( $instructions as $instruction ) {
178			call_user_func_array(array(&$Renderer, $instruction[0]),$instruction[1]);
179		}
180
181		return trim(substr($Renderer->doc, 4, -5));
182	}
183
184	function setLocalLang($text) {
185		$langFile = DOKU_PLUGIN . "formular/lang/$text/lang.php";
186		if (is_File($langFile)) {
187			include($langFile);
188			$this->localLang = $lang;
189		}
190	}
191
192	function getLocalLang($id) {
193		return (isset($this->localLang[$id])) ?
194			$this->localLang[$id] : $this->getLang($id);
195	}
196
197   /**
198	* Function to create some Error-Output
199	*/
200	function insertError($name, $type=3){
201		$header = '<tr><td colspan="2"><span style="color:#FF0000;">';
202		$footer = '</span></td></tr>';
203		switch ($type) {
204		case 0:
205			$error = $this->getLocalLang('name_not_unique').': ' . trim($name);
206			break;
207		case 1:
208			$error = $this->getLocalLang('wrong_nb_of_arguments').': ' . trim($name);
209			break;
210		case 2:
211			$error = $this->getLocalLang('undef_combo').': ' . trim($name);
212			break;
213		case 3:
214			$error = trim($name);
215			break;
216		}
217		return $header.$error.$footer;
218	}
219
220	/**
221	 * Function to write something at beginning of file
222	 */
223	function writeBefore($file, $content) {
224		if (!file_exists($file)) {
225			$handle = fopen($file,'w');
226			fclose($handle);
227		}
228
229		$fOld = file_get_contents($file);
230		$newContent = $content.$fOld;
231		$f = fopen($file,'w') or die($this->getLocalLang('cannot_open'));
232		fwrite($f, $newContent);
233		fclose($f);
234		// file_put_contents($file, $newContent); not used because not implemented below php5
235	}
236
237	function writeDebugInfo($message) {
238		if ($this->getConf('DebugMode')) {
239			$this->writeBefore(DOKU_PLUGIN.'formular/debug.txt', $message."\n");
240		}
241	}
242
243	function constraintError($error) {
244		return "{ \n"
245				. '    $back .= "error='.$error."\";\n"
246				. '    header("Location: $back");'
247				. '    exit();'
248				."\n}\n";
249	}
250
251	/**
252	 * At the moment this just works if the settings are set as follows:
253	 * Use Nice URLs = 2 (DokuWiki Internal)
254	 * Use Slash as Namespace seperator = 0 (Not Checked)
255	 */
256	function writeConstraintsToScript() {
257		$this->writeDebugInfo("Function: writeConstraintsToScript");
258
259		global $conf;
260		if ($conf['userewrite'] != 2 || $conf['useslash'] == 1) {
261			unlink($this->mailPath.'constraint.tmp');
262			$this->writeDebugInfo("Wrong Settings for this.");
263			return;
264		}
265
266		if ($this->internalScript && file_exists($this->mailPath.'constraint.tmp')) {
267			$sgn_begin = "// Formular Plugin - Constraint Signature Begin";
268			$sgn_end = "// Formular Plugin - Constraint Signature End";
269			$sgn_warning = "// Don't remove these lines! Removing can lead to Data Loss in this File!";
270
271			chdir("lib/"); // To ignore the ../ which is used for niceURLs
272			$this->writeDebugInfo("Current Directory: ".getcwd());
273			if(isset($this->scriptPath) && $this->scriptPath != '' && file_exists($this->scriptPath)) {
274				$this->writeDebugInfo("Writing from: ../".$this->mailPath."constraint.tmp to: $this->scriptPath");
275				$constraints = file_get_contents("../".$this->mailPath.'constraint.tmp');
276				$constraints = "<?php \n"
277								. $sgn_begin . "\n"
278								. $sgn_warning . "\n"
279								. $this->getBackLinkVariable() . "\n"
280								. $constraints . "\n"
281								. $sgn_end . "\n ?>\n";
282
283				$lines = file($this->scriptPath);
284				$position_bgn = array_search($sgn_begin."\n", $lines);
285				$position_end = array_search($sgn_end."\n", $lines);
286				if($position_bgn != false && $position_end != false) {
287					array_splice($lines, $position_bgn-1, $position_end-$position_bgn+3);
288				}
289
290				foreach ($lines as $line) {
291					$original_file .= $line;
292				}
293				$file = fopen($this->scriptPath,'w') or die($this->getLocalLang('cannot_open'));
294				fwrite($file, $constraints . $original_file);
295				fclose ($file);
296				//file_put_contents($this->scriptPath, $constraints . $original_file); not used because not implemented below php5
297			} else {
298				$this->writeDebugInfo("Error: ScriptPath not set or File Does not Exist - ScriptPath: $this->scriptPath");
299			}
300			chdir("../");
301		} else {
302			$this->writeDebugInfo("Error: InternalScript: $this->internalScript - Constraint-File: $this->mailPath constraint.tmp");
303		}
304		unlink($this->mailPath.'constraint.tmp');
305	}
306
307	function createMailForm($match) {
308		$this->writeDebugInfo("Creating MailForm");
309		$daten = explode(" ", substr($match, 13, -1));
310		$receipt=$daten[0];
311		$args = explode('"', substr($match, 13, -1));
312
313		// Parameter PHP used?
314		if ($this->getConf('AllowInclude')) {
315			$phpPos = strpos($match, 'PHP:');
316			if ($phpPos !== false) {
317				$include = "include(\""
318								.substr($match, $phpPos +5, strpos($match, '"', $phpPos+5) - ($phpPos+5))
319								."\");\n";
320				$f = fopen($this->mailPath.'incl.tmp','w') or die($this->getLocalLang('cannot_open'));
321				fwrite($f, $include);
322				fclose($f);
323			} else {
324				$include = '';
325			}
326		}
327
328		if (isset($_SERVER["SCRIPT_URI"])) {
329			$URI = $_SERVER["SCRIPT_URI"] . "?id=";
330		} else {
331			$URI = "http://" . $_SERVER["HTTP_HOST"] . $_SERVER["PHP_SELF"] . "?id=";
332		}
333
334		// Parameter Next used?
335		$nextPos = strpos($match, 'NEXT:');
336		if ($nextPos !== false) {
337			$next = substr($match, $nextPos +6 , strpos($match, '"', $nextPos+6) - ($nextPos+6));
338		}
339		if (substr($next, 0, 4) == "www.") {
340			$next = "http://" . $next;
341		} elseif (substr($next, 0, 7) == "http://") {
342			$next = $next;
343		} else {
344			$next = $URI.$next;
345		}
346
347		$mail = 'if ($_POST[\'submit\'] == true) { '. " \n" .
348							'$date=date(\'d.m.Y\'); '. " \n" .
349							'$time=date(\'H,i,s\'); '. " \n" .
350							'$receipt=\'' . $receipt . "'; \n" .
351							'$next="' . $next . "\"; \n" .
352							'$string="'.$this->getLang('received_on').' $date : $time: "';
353		$f = fopen($this->mailPath . 'mail.tmp','w') or die($this->getLocalLang('cannot_open'));
354		fwrite($f, $mail);
355		fclose($f);
356	}
357
358	function createConstraints($line, $name, $error) {
359		$grepPos = strpos($line, 'grep=');
360		$grepnotPos = strpos($line, 'grepnot=');
361		$minLengthPos = strpos($line, 'minLength=');
362		$maxLengthPos = strpos($line, 'maxLength=');
363		$valueTypePos = strpos($line, 'valueType=');
364		$evalFunctionPos = strpos($line, 'evalFunction=');
365		$lengthPos = strpos($line, 'length=');
366		$grepnotPos = strpos($line, 'grepnot=');
367
368		if ($grepPos !== false) {
369			$grep = substr($line, $grepPos+6 ,
370									strpos($line, '"', $grepPos+6) - ($grepPos+6));
371			$constraint .= 'if (! preg_match(\''.$grep.'\', $_POST[\''.$name.'\']))'."\n"
372									.$this->constraintError($error);
373		}
374		if($grepnotPos !== false) {
375			$grepnot = substr($line, $grepnotPos+9 ,
376									strpos($line, '"', $grepnotPos+9) - ($grepnotPos+9));
377			$constraint .= 'if(preg_match(\'' . $grepnot . '\', $_POST[\'' . $name . '\']))' . "\n"
378									.$this->constraintError($error);
379		}
380		if ($lengthPos !== false) {
381			(int) $length = substr($line, $lengthPos+8 ,
382													strpos($line, '"', $lengthPos+8) - ($lengthPos+8));
383			if (! is_numeric($length)) {
384				$data .= $this->insertError($this->getLocalLang('len_not_num'));
385			}
386			$constraint .= 'if (strlen($_POST[\''.$name.'\']) != '.$length.')'."\n"
387									.$this->constraintError($error);
388		}
389		if ($minLengthPos !== false) {
390			(int) $minLength = substr($line, $minLengthPos+11 ,
391														strpos($line, '"', $minLengthPos+11) - ($minLengthPos+11));
392			if (! is_numeric($minLength)) {
393				$data .= $this->insertError($this->getLocalLang('minlen_not_num'));
394			}
395			$constraint .= 'if (strlen($_POST[\''.$name.'\']) < '.$minLength.')'."\n"
396									.$this->constraintError($error);
397		}
398		if ($maxLengthPos !== false) {
399			(int) $maxLength = substr($line, $maxLengthPos+11 ,
400														strpos($line, '"', $maxLengthPos+11) - ($maxLengthPos+11));
401			if (! is_numeric($maxLength)) {
402				$data .= $this->insertError($this->getLocalLang('maxlen_not_num'));
403			}
404			$constraint .= 'if (strlen($_POST[\'' . $name . '\']) > '.$maxLength.')'."\n"
405									.$this->constraintError($error);
406		}
407		if ($valueTypePos !== false) {
408			$valueType = substr($line, $valueTypePos+11 ,
409											strpos($line, '"', $valueTypePos+11) - ($valueTypePos+11));
410			switch ($valueType) {
411			case 'integer' :
412				$constraint .= 'if( (! preg_match("/^\d+$/", $_POST[\''.$name.'\'])) '
413										.'|| (! is_numeric($_POST[\'' . $name . '\'])) )'."\n"
414										. $this->constraintError($error);
415				break;
416			case 'float' :
417				$constraint .= 'if(! is_numeric($_POST[\''.$name.'\']))'."\n "
418										.$this->constraintError($error);
419				break;
420			case 'eMail' :
421				$constraint .= '$pattern = "/^[A-z0-9\._-]+@[A-z0-9][A-z0-9-]*(\.[A-z0-9_-]+)*\.([A-z]{2,6})$/";';
422				$constraint .= "\n"
423										.'if (! preg_match($pattern, $_POST[\''.$name.'\']))'."\n"
424										.$this->constraintError($error);
425				break;
426			}
427		}
428		if($grepnotPos !== false) {
429				$grepnot = substr($line, $grepnotPos+9 , strpos($line, '"', $grepnotPos+9) - ($grepnotPos+9));
430				$constraint .= 'if(preg_match(\'' . $grepnot . '\', $_POST[\'' . $name . '\']))' . "\n"
431						. $this->constraintError($error);
432		}
433
434		if ($this->getConf('AllowInclude')) {
435			if ($evalFunctionPos !== false) {
436				$evalFunction = substr($line, $evalFunctionPos+14 ,
437													strpos($line, '"', $evalFunctionPos+14) - ($evalFunctionPos+14));
438				$constraint .= 'if(! '.$evalFunction.'($_POST[\''.$name.'\']))'."\n"
439										.$this->constraintError($error);
440			}
441		}
442
443		return $constraint;
444	}
445
446	function createFileElement($text, $width, $value) {
447		$result = '<tr><td>'
448					.$this->parsed($text)
449					.'</td><td>'
450					.'<input class="edit" type="file" size="50" '
451					.'name="file[formular][]"';
452
453		if(isset($width) and $width != "") {
454			$result .= ' style="width:'.$width.'px;"';
455		}
456		if(isset($value) and $value != "") {
457			$result .= ' value="' . $value . '"';
458		}
459
460		$result .= ' /></td></tr>';
461		return $result;
462	}
463
464	function createTextbox($name, $text, $width, $value) {
465		$result = '<tr><td>'
466					.$this->parsed($text)
467					.'</td><td>'
468					.'<input class="edit" type="text" '
469					."name=\"$name\"";
470
471		if(isset($width) and $width != "") {
472			$result .= ' style="width:'.$width.'px;"';
473		}
474		if(isset($value) and $value != "") {
475			$result .= 'value="' . $value . '"';
476		}
477
478		$result .= ' /></td></tr>';
479		return $result;
480	}
481
482	function createHidden($name, $text) {
483		if ($name == 'lang') {
484			$this->setLocalLang($text);
485		}
486		return '<input type="hidden" '
487				.'name="'.$name
488				.'" value="'.$this->phpParsed($text).'" />';
489	}
490
491	function createPassbox($name, $text, $width) {
492		$result = '<tr><td>'
493					.$this->parsed($text)
494					.'</td><td>'
495					.'<input class="edit" type="password" '
496					."name=\"$name\"";
497
498		if(isset($width) and $width != "") {
499			$result .= ' style="width:'.$width.'px;"';
500		}
501		$result .= ' /></td></tr>';
502		return $result;
503	}
504
505	function createSelectBox($name, $text, $width, $options, $value) {
506		$result = '<tr><td>'
507					.  $this->parsed($text)
508					.'</td><td>'
509					.'<select name="' . $name . '" size="1"';
510
511		if(isset($width) and $width != "") {
512			$result .= ' style="width:'.$width.'px;"';
513		}
514
515		$result .= '><option value="n/a">[ '.$this->getLocalLang('pls_choose').' ]</option>';
516
517		$first = '';
518		// create Options
519		foreach ($options as $option) {
520			if(trim($option) == trim($value)) {
521				$checked = 'selected';
522			} else {
523				$checked = '';
524			}
525
526			// this is for escape sequences
527			if ($option[strlen($option)-1] == "\\" && $first != '') {
528				$first = $first . ',' . substr($option, 0, -1);
529			} else if ($option[strlen($option)-1] == "\\" && $first == '') {
530				$first = substr($option, 0, -1);
531			} else if ($option[strlen($option)-1] != "\\" && $first != '') {
532				$result .= "<option $checked>".$first.','.$option."</option>";
533				$first = '';
534			} else if ($option[strlen($option)-1] != "\\" && $first == '') {
535				$result .= "<option $checked>".$option."</option>";
536			}
537		}
538
539		$result .= '</select></td></tr>';
540		return $result;
541	}
542
543	function createTextarea($name, $text, $value, $rows, $width) {
544		$result = '<tr><td>'
545				.$this->parsed($text)
546				.'</td><td>'
547				.'<textarea class="edit" name="'.$name
548				.'" rows="'.$rows.'"';
549
550		if(isset($width) and $width != "") {
551			$result .= ' style="width:'.$width.'px;"';
552		}
553		$result .= '>';
554		if(isset($value) and $value != "") {
555			$result .= str_replace("<br/>",chr(13).chr(10),$value);
556		}
557		$result .= '</textarea></td></tr>';
558
559		return $result;
560	}
561
562	function createRadioButton($name, $text, $options, $value) {
563		foreach ($options as $option) {
564			// first is for escape sequence to print commata
565			$first = '';
566			$header = '';
567
568			if ($option[strlen($option)-1] == "\\") {
569				$first = substr($option, 0, -1);
570				continue;
571			}
572			if ($first != '') {
573				$first = $first.",";
574				$i = 1;
575			} else {
576				$i = 0;
577			}
578
579			if (trim($option) == trim($value) || trim($first.$option) == trim($value)) {
580				$checked = 'checked="checked"';
581			} else {
582				$checked = '';
583			}
584			// Is this the first Option? If first is set the first Option has the index 1 not 0
585			if ($option == $options[$i]) {
586				if ($value=='') $checked = 'checked="checked"';
587				$header = $this->parsed($text);
588			}
589
590			$result .= '<tr><td>'.$header.'</td><td>'
591						.'<input type="radio" name="'.$name
592						.'" value="'.$first.$option.'" '
593						.$checked.'>&nbsp;&nbsp;'
594						.$first.$option
595						.'</td></tr>';
596		}
597		return $result;
598	}
599
600	function setMailFile() {
601		$this->writeDebugInfo("Function: setMailFile()");
602		global $ID;
603        $mailFilePath = $this->getConf('mailPath');
604		if (! is_dir($mailFilePath)) mkdir($mailFilePath, 0777);
605
606		// support namespaces
607		$idSplit = explode(":", $ID);
608		if (count($idSplit) > 1) {
609			for ($i = 1; $i < count($idSplit); $i++) {
610				$mailFilePath .= $idSplit[($i-1)] . "/";
611				if (! is_dir($mailFilePath)) mkdir($mailFilePath, 0777);
612			}
613			$this->mailFile = $mailFilePath . "form_" . $idSplit[$i-1] . ".php";
614		} else {
615			$this->mailFile = $mailFilePath . "form_" . $ID . ".php";
616		}
617		$this->mailPath = $mailFilePath;
618		$this->writeDebugInfo("MailPath: $mailFilePath");
619		$this->writeDebugInfo("MailFile: $this->mailFile");
620	}
621
622	function getFileUploadScript() {
623		return '$boundary = strtoupper(md5(uniqid(time())));' . "\n"
624				. '$mail_header  = "From: '.$this->getConf('mailFrom').'\n";' . "\n"
625				. '$mail_header .= "MIME-Version: 1.0";' . "\n"
626				. '$mail_header .= "\nContent-Type: multipart/mixed; boundary=$boundary";' . "\n"
627				. '$mail_header .= "\n\nThis is a multi-part message in MIME format  --  Dies ist eine mehrteilige Nachricht im MIME-Format";' . "\n"
628				. '$mail_header .= "\n--$boundary";' . "\n"
629				. '$mail_header .= "\nContent-Type: text/plain";' . "\n"
630				. '$mail_header .= "\nContent-Transfer-Encoding: 8bit";' . "\n"
631				. '$mail_header .= "\n\n$string";' . "\n"
632				. '$i = 0;' . "\n"
633				. 'while (is_uploaded_file($_FILES[\'file\'][\'tmp_name\'][\'formular\'][$i])) {' . "\n"
634				. '    if ($_FILES[\'file\'][\'size\'][\'formular\'][$i] > ($_POST[\'file_maxsize\'] * 1000000)) {' . "\n"
635				. '        $back .= "error='.$this->getLocalLang('filesize_exceeded').'";' . "\n"
636				. '        header("Location: $back");' . "\n"
637				. '        exit();' . "\n"
638				. '    }' . "\n"
639				. '    $file_content = fread(fopen($_FILES[\'file\'][\'tmp_name\'][\'formular\'][$i],"r"),$_FILES[\'file\'][\'size\'][\'formular\'][$i]);' . "\n"
640				. '    //$file_content = readfile($_FILES[\'file\'][\'tmp_name\'][\'formular\'][$i]);' . "\n"
641				. '    $file_content = chunk_split(base64_encode($file_content));' . "\n"
642				. '    $mail_header .= "\n--$boundary";' . "\n"
643				. '    $mail_header .= "\nContent-Type: ".$_FILES[\'file\'][\'type\'][\'formular\'][$i]."; name=\"".$_FILES[\'file\'][\'name\'][\'formular\'][$i]."\"";' . "\n"
644				. '    $mail_header .= "\nContent-Transfer-Encoding: base64";' . "\n"
645				. '    $mail_header .= "\nContent-Disposition: attachment; filename=\"".$_FILES[\'file\'][\'name\'][\'formular\'][$i]."\"";' . "\n"
646				. '    $mail_header .= "\n\n$file_content";' . "\n"
647				. '    $i++;' . "\n"
648				. '}' . "\n"
649				. '$mail_header .= "\n--$boundary--";' . "\n";
650	}
651
652	// create Constraints Backlink
653	function getBackLinkVariable() {
654		return '$back = $_POST["formular_url"]."?";'
655				. "\n".'$blacklist=array("next","formular_url","submit","error","file_maxsize");'
656				. "\n".'foreach($_POST as $key_name => $key_value) {'
657				. "\n".'  if (in_array($key_name, $blacklist)) continue;'
658				. "\n".'  $key_value = str_replace(chr(10),"<br/>",$key_value);'
659				. "\n".'  $key_value = str_replace(chr(13),"",$key_value);'
660				. "\n".'  $back .= $key_name . "=". utf8decode($key_value) . "&";'
661				. "\n}\n";
662	}
663
664	//Only for Internal USE!
665	function printAllInternInformation() {
666		echo "\nMETHODS: \n";
667		print_r(get_class_methods($this));
668		echo "\nMETHODS-END: \n";
669		echo "\nVARIABLES: \n";
670		print_r(get_object_vars($this));
671		echo "\nVARIABLES-END: \n";
672		echo "\nGLOBALS: \n";
673		print_r($GLOBALS);
674		echo "\nGLOBALS-END: \n";
675	}
676
677	/**
678	* Handle the match
679	*/
680	function handle($match, $state, $pos, &$handler) {
681		global $ID;
682
683		switch ($state) {
684		case DOKU_LEXER_ENTER :
685			$this->writeDebugInfo("DOKU_LEXER_ENTER"); $this->writeDebugInfo("WorkingDirectory: ".getcwd());
686			$this->setMailFile();
687			// MAILTO-Formular
688			if (substr($match, 6, 7) == "MAILTO:") {
689				$this->createMailForm($match);
690				$action = DOKU_URL . $this->mailFile;
691			} else {
692				$args = explode('"', $match);
693				//DOKUWIKI-PAGE
694				if ((substr($args[1], 0, 7) != "http://")
695						&& (substr($args[1], -4, 4) != ".php")
696						&& (substr($args[1], 0, 3) != "www")) {
697					$this->scriptPath = "doku.php?id=" . $args[1];
698				//External Link without HTTP
699				} elseif (substr($args[1], 0, 4) == "www.") {
700					$this->scriptPath = "http://". $args[1];
701				//External Link with HTTP
702				} elseif (substr($args[1], 0, 7) == "http://") {
703					$this->scriptPath = $args[1];
704 				// Internal PHP-Script-Path
705				} elseif (substr($args[1], -4, 4) == ".php") {
706					$this->scriptPath = $args[1];
707					$this->internalScript = true;
708				} else {
709					$this->scriptPath = $args[1];
710				}
711
712				$this->writeDebugInfo("ScriptPath: $this->scriptPath");
713				$action = $this->scriptPath;
714			}
715			$data = "<form action=\"$action\" method=\"post\" accept-charset=\"utf-8\" "
716						. "enctype=\"multipart/form-data\"> <table class=\"formular\">";
717
718			if (isset($_GET['error'])) {
719				$data .= '<tr><td colspan="2"><span style="color:#FF0000;">'
720							. $_GET['error']
721							. '</span></td></tr>';
722			}
723			$data .= $this->createHidden("formular_url", DOKU_URL."doku.php/".$ID);
724			break;
725
726		case DOKU_LEXER_EXIT :
727			$this->writeDebugInfo("DOKU_LEXER_EXIT_BEGIN");
728			$data = '</table></form>';
729			if (is_file($this->mailPath.'mail.tmp')) {
730                $subject = $this->getConf('mailSubject');
731                $mail = '; '." \n"
732                		. '$string .= "\nSender: ".$_SERVER[\'LOGON_USER\'].$_SERVER[\'REMOTE_USER\'];'." \n";
733                $mail .= $this->getFileUploadScript();
734				$mail .= 'mail($receipt, \''.$subject.'\', "", $mail_header);'
735						. " \n"
736						. 'header("Location: $next"); '
737						. " \n } \n ?>";
738
739				$f = fopen($this->mailPath.'mail.tmp','a') or die($this->getLocalLang('cannot_open'));
740				fwrite($f, $mail);
741				fclose($f);
742
743				$mailhead = "<?php\n";
744				if (is_file($this->mailPath.'incl.tmp')) {
745					$mailhead .= file_get_contents($this->mailPath.'incl.tmp');
746					unlink($this->mailPath.'incl.tmp');
747				}
748				// create Constraints Backlink
749				$mailhead .= $this->getBackLinkVariable();
750
751				$this->writeBefore ($this->mailPath.'mail.tmp', $mailhead);
752				$this->writeDebugInfo("Copy From ".$this->mailPath.'mail.tmp - To: '.$this->mailFile);
753				copy($this->mailPath.'mail.tmp', $this->mailFile);
754				unlink($this->mailPath.'mail.tmp');
755			// Write Constraints to self written Script-Files
756			} elseif(is_file($this->mailPath.'constraint.tmp')) {
757				$this->writeConstraintsToScript();
758			}
759			$this->writeDebugInfo("DOKU_LEXER_EXIT_END");
760			break;
761
762		// Complete Body between <FORM> and </FORM>
763		default:
764			$lines = explode(';', $match);
765			// This is for global ; escape sequence
766			foreach ($lines as $index => $line){
767				if (isset($firstPart) && $firstPart != '') {
768					$lines[$index] = $firstPart.$line;
769					$line = $lines[$index];
770					unset($firstPart);
771				}
772				if (substr($line, -1) == '\\') {
773					$firstPart = substr($line, 0, -1).';';
774					unset($lines[$index]);
775					continue;
776				}
777			}
778			$nameArray = array();
779
780			foreach ($lines as $line) {
781				$explBlank = explode(' ', $line);
782				$explQuoteMark = explode('"', $line);
783				$lastArgs = explode(' ', trim($explQuoteMark[count($explQuoteMark)-1]));
784				$name = trim($explBlank[1]);
785				$text = trim($explQuoteMark[1]);
786				$value = $_GET["$name"];
787
788				// Keyword
789				switch (trim($explBlank[0])) {
790				case 'Textbox':
791				case 'Passbox':
792				case 'Hidden' :
793					// number of arguments given is correct?
794					if (count($explQuoteMark) != 3 || count($explBlank) < 2) {
795						$data .= $this->insertError($name, 1);
796						break;
797					}
798					// routine to check if names are unique
799					if (in_array($name, $nameArray)) {
800						$data .= $this->insertError($name, 0);
801						break;
802					}
803					array_push($nameArray, $name);
804
805					$width = $lastArgs[0];
806					if (trim($explBlank[0]) == 'Textbox') {
807						$data .= $this->createTextbox($name, $text, $width, $value);
808					} elseif (trim($explBlank[0]) == 'Passbox') {
809						$data .= $this->createPassbox($name, $text, $width);
810					} else {
811						$data .= $this->createHidden($name, $text);
812					}
813					if (is_file($this->mailPath.'mail.tmp')) {
814						$mail .= " . \"\\n $name ==> \" . \$_POST['$name'] " . "\n";
815					}
816					break;
817
818				case 'Select' :
819					// SelectBox with manual Options given by a list
820					if (count($explQuoteMark) == 5
821							&& count(explode(' ', trim($explQuoteMark[4]))) == 1
822							&& count(explode(' ', trim($explQuoteMark[0]))) == 2
823							&& trim($explQuoteMark[2]) == '' ) {
824						$width = $lastArgs[0];
825						$optionsList = $explQuoteMark[3];
826						$options = explode(",", $optionsList);
827					}
828					// SelectBox defined in wikipage select
829					elseif (count($explQuoteMark) == 3
830									&& count(explode(' ', trim($explQuoteMark[0]))) == 2
831									&& (count(explode(' ', trim($explQuoteMark[2]))) == 2
832											|| count(explode(' ', trim($explQuoteMark[2]))) == 1)) {
833						$optName = $lastArgs[0];
834						$width = $lastArgs[1];
835
836                        $selectPage = $this->getConf('selectPage');
837
838						$found = 0;
839						$selectPath = "data/pages";
840						$selectSplit = explode(':', $selectPage);
841						foreach ($selectSplit as $split) {
842							$selectPath .= "/" . $split;
843						}
844						$selectPath .= ".txt";
845
846						if (file_exists($selectPath)){
847							$fileLines = file($selectPath);
848							foreach ($fileLines as $fileLine) {
849								$lineElements = explode(' ', $fileLine);
850								// Is the defined name equal to name in argument list?
851								if ($lineElements[0] == $optName) {
852									$options = explode(",", substr($fileLine, strlen($lineElements[0])+1));
853									$found = 1;
854								}
855							}
856						}
857						// Named SelectBox not found in WikiPage
858						if($found == 0) {
859							$data .= $this->insertError($optName, 2);
860							break;
861						}
862					} else { // arguments where not correct
863						$data .= $this->insertError($name, 1);
864						break;
865					}
866
867					// routine to check if names are unique
868					if (in_array($name, $nameArray)) {
869						$data .= $this->insertError($name, 0);
870						break;
871					}
872					array_push($nameArray, $name);
873
874					if (is_file($this->mailPath.'mail.tmp')) {
875						$mail .= " . \"\\n $name ==> \" . \$_POST['$name'] " . "\n";
876					}
877
878					$data .= $this->createSelectBox($name, $text, $width, $options, $value);
879					break;
880
881				case 'Checkbox' :
882					// number of arguments given is correct?
883					if (count($explQuoteMark) != 3
884							|| count(explode(' ', trim($explQuoteMark[0]))) != 2
885							|| count(explode(' ', trim($lastArgs))) != 1 ) {
886						$data .= $this->insertError($name, 1);
887						break;
888					}
889					// routine to check if names are unique
890					if (in_array($name, $nameArray)) {
891						$data .= $this->insertError($name, 0);
892						break;
893					}
894					array_push($nameArray, $name);
895
896					// should checkbox be checked
897					// Not working proberly if Standard=checked but not checked when sending
898					// In this case the value is not set and therefore it is checked again when coming back
899					$checked = '';
900					if (isset($value)) {
901						if ($value='on') $checked = 'CHECKED';
902					} else {
903						if ($lastArgs[0] == "1") $checked = 'CHECKED';
904					}
905
906					if (is_file($this->mailPath.'mail.tmp')) {
907						$mail .= " . \"\\n $name ==> \" . \$_POST['$name'] " . "\n";
908					}
909
910					$data .= '<tr><td colspan="2">'
911								.'<input type="checkbox" '
912								.'name="'.$name.'" '
913								.$checked
914								.'  value="'.$text.'"/>&nbsp;&nbsp;'
915								.$this->parsed($text)
916								.'</td></tr>';
917					break;
918
919				case 'Textarea' :
920					// number of arguments given is correct?
921					if (count($explQuoteMark) != 3
922							|| ( count($lastArgs) != 1
923									&& count($lastArgs) != 2 )) {
924						$data .= $this->insertError($name, 1);
925						break;
926					}
927
928					// routine to check if names are unique
929					if (in_array($name, $nameArray)) {
930						$data .= $this->insertError($name, 0);
931						break;
932					}
933					array_push($nameArray, $name);
934
935					if (is_file($this->mailPath.'mail.tmp')) {
936						$mail .= " . \"\\n $name ==> \\\" \" . \$_POST['$name'] . \" \\\" \" " . "\n";
937					}
938
939					$rows = $lastArgs[0];
940					$width = $lastArgs[1];
941					$data .= $this->createTextarea($name, $text, $value, $rows, $width);
942					break;
943
944				case 'Submit' :
945					// number of arguments given is correct?
946					if ( count($lastArgs) != 1
947							|| count($explQuoteMark) != 3) {
948						$data .= $this->insertError($explQuoteMark[1], 1);
949						break;
950					}
951
952					$data .= '<tr><td></td><td>'
953								.'<input class="button" type="submit" name="submit" '
954								.'value="'.$explQuoteMark[1]
955								.'" style="width:'.$lastArgs[0].'px;" />'
956								.'</td></tr>';
957					break;
958
959				case 'Static' :
960					switch (count($explQuoteMark)) {
961					case 3 :
962						$data .= "<tr><td colspan=\"2\">"
963									.$this->parsed($explQuoteMark[1])
964									."</td></tr>";
965						break;
966					case 5 :
967						$data .= "<tr><td>"
968									.$this->parsed($explQuoteMark[1])
969									."</td><td>"
970									.$this->parsed($explQuoteMark[3])
971									."</td></tr>";
972						break;
973					default :
974						$data .= $this->insertError($explQuoteMark[0], 1);
975					}
976					break;
977
978				case 'Radio' :
979					// number of arguments given is correct?
980					if (count($explQuoteMark) != 5
981							|| count(explode(' ', trim($explQuoteMark[0]))) != 2
982							|| count($lastArgs) > 1
983							|| $lastArgs[0] != '') {
984						$data .= $this->insertError($name, 1);
985						break;
986					}
987					// routine to check if names are unique
988					if (in_array($name, $nameArray)) {
989						$data .= $this->insertError($name, 0);
990						break;
991					}
992					array_push($nameArray, $name);
993
994					$options = explode(',', $explQuoteMark[3]);
995					$data .= $this->createRadioButton($name, $text, $options, $value);
996
997					if (is_file($this->mailPath . 'mail.tmp')) {
998						$mail .= " . \"\\n $name ==> \" . \$_POST['$name'] " . "\n";
999					}
1000					break;
1001
1002				case 'File' :
1003					// number of arguments given is correct?
1004					if (count($explQuoteMark) != 3
1005							|| count($explBlank) < 2
1006							|| count($lastArgs) < 1
1007							|| $lastArgs[0] == '') {
1008						$data .= $this->insertError($name, 1);
1009						break;
1010					}
1011
1012					$maxsize = $lastArgs[0];
1013					$width = $lastArgs[1];
1014					$data .= $this->createFileElement($text, $width, $value);
1015					$data .= $this->createHidden('file_maxsize', $maxsize);
1016					break;
1017
1018				case 'Line' :
1019					$data .= '<tr><td colspan="2">&nbsp;</td></tr>';
1020					break;
1021
1022				case 'Buttons' :
1023					// number of arguments given is correct?
1024					if (count($explQuoteMark) != 5
1025							|| count($lastArgs) != 1
1026							|| trim($explQuoteMark[2]) != '') {
1027						$data .= $this->insertError('Buttons', 1); //TODO: localize string
1028						break;
1029					}
1030
1031					$data .= '<tr><td></td><td> '
1032								.'<input class="button" type="submit" '
1033								.'value="' . $explQuoteMark[1]
1034								.'" style="width:'.$lastArgs[0].'px;" />'
1035								.'<input class="button" type="reset" '
1036								.'value="'.$explQuoteMark[3]
1037								.'" style="width:'.$lastArgs[0].'px;" /> '
1038								.'</td></tr>';
1039					break;
1040
1041				case 'Constraint' :
1042					// number of arguments given is correct?
1043					if (count($explQuoteMark) < 3
1044							|| count(explode(' ', trim($explQuoteMark[0]))) != 2) {
1045						$data .= $this->insertError('Constraint ' . $name, 1);
1046						break;
1047					}
1048					$error = $explQuoteMark[1];
1049					$constraint .= $this->createConstraints($line, $name, $error);
1050					break;
1051
1052				case '':
1053					break;
1054
1055				// keyword was not recognised
1056				default:
1057					$data .= '<tr><td colspan="2"><span style="color:#FF0000;">'
1058								.$this->getLang('wrong_kw').' ' . trim($explBlank[0]) . '!'
1059								.'</span></td></tr>';
1060					break;
1061				} //switch body
1062			} //foreach line
1063
1064			// File for creating Mail Script
1065			if ($mail != '') {
1066				if (isset($constraint) && $constraint != '') {
1067					$this->writebefore($this->mailPath.'mail.tmp', $constraint);
1068				}
1069				// file_put_contents($mailFilePath . 'mail.tmp', $mail, FILE_APPEND) or die("Could not write to mailscript temp file: $php_errormsg");
1070				$f = fopen($this->mailPath.'mail.tmp','a') or die($this->getLocalLang('cannot_open'));
1071				fwrite($f, $mail);
1072				fclose($f);
1073			} else {
1074				if (isset($constraint) && $constraint != '' && $this->internalScript) {
1075					$this->writebefore($this->mailPath.'constraint.tmp', $constraint);
1076				}
1077			}
1078		} //switch $state
1079
1080		// return created string
1081		return $data;
1082	}
1083
1084	/**
1085	 * Create output
1086	 */
1087	function render($mode, &$renderer, $data) {
1088		if ($mode == 'xhtml') {
1089            $renderer->info['cache'] = false;
1090			$renderer->doc .= $data;
1091			return true;
1092		}
1093		return false;
1094	}
1095}
1096