Skip to content

Instantly share code, notes, and snippets.

@Zegnat
Created April 18, 2011 10:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Zegnat/925103 to your computer and use it in GitHub Desktop.
Save Zegnat/925103 to your computer and use it in GitHub Desktop.
Form builder
<?php
# ### ### ### ### ### ### ### ### ### ###
# HEAD
header('Content-Type: text/html; charset=utf-8');
error_reporting(E_ALL);
ini_set('display_errors', '1');
ini_set('memory_limit', '12M');
function pre_var_dump() {
$args = func_get_args();
echo '<pre>',call_user_func_array('var_dump',$args),'</pre>';
}
# ### ### ### ### ### ### ### ### ### ###
# SETTINGS
if (!defined('MAXDEPTH')) define('MAXDEPTH',ini_get('max_input_nesting_level')-2);
if (!defined('DBHOST')) define('DBHOST','localhost:8889');
if (!defined('DBNAME')) define('DBNAME','school');
if (!defined('DBUSER')) define('DBUSER','root');
if (!defined('DBPASS')) define('DBPASS','root');
# ### ### ### ### ### ### ### ### ### ###
# DATABASE CONNECT
mysql_connect(DBHOST,DBUSER,DBPASS) or die(mysql_error());
mysql_select_db(DBNAME) or die(mysql_error());
# ### ### ### ### ### ### ### ### ### ###
# START
# Create one central variable:
$form = isset($_POST['form'])?$_POST['form']:array();
unset($_POST['form']);
# Are there any actions with parameters?
if (isset($_POST['action'])&&count($action=explode(' ',$_POST['action']))>1) {
if ($action[0]=='add') {
if (in_array($action[1],array('text','textarea','checkbox'))) $form[] = array('type'=>$action[1],'name'=>'');
}
else if ($action[0]=='repeat') {
$walkway = explode(',',$action[1]);
if (count($walkway)<MAXDEPTH) {
$repeater = &$form;
foreach ($walkway as $step) $repeater = &$repeater[$step];
$repeater = array('type'=>'repeat','name'=>'','min'=>0,'max'=>-1,'value'=>array($repeater));
}
}
else if ($action[0]=='move') {
$walkway = explode(',',$action[2]);
if ($action[1]=='down') $walkway[(count($walkway)-1)]++;
if (end($walkway)>0) {
$lower = &$form;
foreach ($walkway as $step) $lower = &$lower[$step];
$move = $lower;
if (!!$move) {
$upper = &$form;
$walkway[(count($walkway)-1)]--;
foreach ($walkway as $step) $upper = &$upper[$step];
$lower = $upper;
$upper = $move;
}
}
}
else if ($action[0]=='merge') {
$walkway = explode(',',$action[2]);
$merge = &$form;
foreach ($walkway as $step) $merge = &$merge[$step];
$repeater = &$form;
for ($i=0,$l=count($walkway);$i<($l-1);$i++) $repeater = &$repeater[$walkway[$i]];
$repeater[end($walkway)-1]['value'][] = $merge;
$action = array('delete',$action[2]);
}
else if ($action[0]=='out') {
$walkway = explode(',',$action[2]);
$jumper = &$form;
foreach ($walkway as $step) $jumper = &$jumper[$step];
$parent = &$form;
for ($i=0,$l=count($walkway);$i<($l-3);$i++) $parent = &$parent[$walkway[$i]];
array_splice($parent,$walkway[count($walkway)-3]+1,0,array($jumper));
$action = array('delete',$action[2]);
}
# Deleter, no else, can be triggered by above IFs.
if ($action[0]=='delete') {
do {
$element = &$form;
for ($i=0,$arr=explode(',',$action[1]),$l=count($arr);$i<($l-1);$i++) $element = &$element[$arr[$i]];
array_splice($element,end($arr),1);
$action[1] = false;
if (in_array('value',$arr)) {
$element = &$form;
for ($i=0,$arr=array_slice($arr,0,count($arr)-2),$l=count($arr);$i<$l;$i++) $element = &$element[$arr[$i]];
if (count($element['value'])<1) $action[1] = implode(',',$arr);
}
} while ($action[1]!==false);
}
}
# Are there any actions without parameters?
else if (isset($_POST['action'])&&strlen($action=$_POST['action'])>0) {
if ($action=='cancel'||$action=='load') {
$table = $action=='load'?intval($_POST['formselect']):(strlen($id=$_POST['formid'])>0&&is_int(intval($id))?intval($id):false);
if ($action=='load'&&!$table) {
pre_var_dump('Nothing to load.');
} else if ($table) {
$info = mysql_query("SELECT * FROM db_form_settings WHERE id=".$table) or die(mysql_error());
$arr = mysql_fetch_array($info);
$_POST['formid'] = $arr['id'];
$_POST['formname'] = $arr['name'];
$form = loadList($table);
} else {
$action = 'new';
}
}
else if ($action=='drop'&&$id=intval($_POST['formselect'])) {
$array = array();
$tables = mysql_query("SELECT table_name FROM information_schema.TABLES WHERE TABLE_SCHEMA = '".DBNAME."' AND TABLE_NAME LIKE 'db_form_".$id."%'") or die(mysql_error());
while($row = mysql_fetch_assoc($tables)) $array[] = $row['table_name'];
mysql_query("DROP TABLE ".implode(',',$array)) or die(mysql_error());
mysql_query("DELETE FROM db_form_settings WHERE id='".$id."'") or die(mysql_error());
if ($id==$_POST['formid']) $action = 'new';
}
else if ($action=='save') {
$error = array();
$QUERY = array();
if (strlen($name=trim($_POST['formname']))==0) $error[] = 'You must enter a name for your form.';
if (count($form)==0) $error[] = 'You must build a form for it to be saved.';
if (isset($_POST['formid'])&&strlen($_POST['formid'])>0&&is_int(intval($_POST['formid']))) {
$QUERY[] = "UPDATE db_form_settings SET name='".mysql_real_escape_string($_POST['formname'])."' WHERE id='".intval($_POST['formid'])."'";
} else {
$QUERY[] = "INSERT INTO db_form_settings(name) VALUE('".mysql_real_escape_string($_POST['formname'])."')";
# Don’t forget to set the new formid!
$get = mysql_query("SHOW TABLE STATUS LIKE 'db_form_settings'") or die(mysql_error());
$arr = mysql_fetch_array($get);
$_POST['formid'] = $arr['Auto_increment'];
mysql_free_result($get);
}
$mid = $_POST['formid'];
$ids = array(array($mid,$form));
$subs = 0;
do {
list($id, $items) = array_shift($ids);
$subs++;
$table = 'db_form_'.$id;
$QUERY[] = "DROP TABLE IF EXISTS ".$table;
$QUERY[] = "CREATE TABLE ".$table."(id INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(id), type TINYTEXT NOT NULL, name TEXT NOT NULL, required INT, min INT, max INT, subform TINYTEXT)";
foreach ($items as $i=>$item) {
if (strlen(trim($item['name']))==0&&!in_array('You must enter a name for every form item.',$error)) $error[] = 'You must enter a name for every form item.';
if ($i==0) $QUERY[] = "INSERT INTO ".$table." VALUES";
else $QUERY[count($QUERY)-1] .= ", ";
$QUERY[count($QUERY)-1] .= "(NULL,'".mysql_real_escape_string($item['type'])."','".mysql_real_escape_string($item['name'])."','".(isset($item['required'])?1:0)."',";
if ($item['type']=='repeat') {
$nid = $mid.'_'.$subs;
$QUERY[count($QUERY)-1] .= "'".(($mi=$item['min'])<=0||!is_int(intval($mi))?'0':intval($mi))."','".(($ma=$item['max'])<=0||$ma<$mi||!is_int(intval($ma))?0:intval($ma))."','".$nid."')";
if ($mi==1&&$ma==1) $error[] = 'You should not use a repeater when you don’t allow it to be repeated.';
$ids[] = array($nid,$item['value']);
} else $QUERY[count($QUERY)-1] .= "NULL,NULL,NULL)";
}
} while(count($ids));
if (!count($error)) {
foreach ($QUERY as $statement) mysql_query($statement) or die(mysql_error());
}
}
# Empty form, no else, can be triggered by above IFs.
if ($action=='new') {
$_POST['formid'] = '';
$_POST['formname'] = '';
$form = array();
}
}
# ### ### ### ### ### ### ### ### ### ###
# DEBUG
//echo '<pre><h3>Action</h3></pre>',pre_var_dump(isset($action)?$action:null),'<pre><h3>$_POST</h3></pre>',pre_var_dump($_POST),'<pre><h3>$form</h3></pre>',pre_var_dump($form);
# ### ### ### ### ### ### ### ### ### ###
# FUNCTIONS
# These are used mostly for recursion.
function array_add($array,$value) { $array[] = $value; return $array; };
function loadList($id) {
$form = array();
$table = mysql_query("SELECT * FROM db_form_".$id) or die(mysql_error());
while($item = mysql_fetch_array($table,MYSQL_ASSOC)) {
if ($item['type']=='repeat') $form[] = array_merge(array_slice($item,1,5),array('value'=>loadList($item['subform'])));
else $form[] = array_slice($item,1,3);
}
return $form;
}
function drawList($base,$depth=array()) {
$deep = '';
$id = '';
$prev = false;
foreach ($depth as $i) {
$deep .= '['.$i.']';
$id .= $i.',';
}
foreach ($base as $i=>$element) {
if (isset($element['type'])&&in_array($type=$element['type'],array('text','textarea','checkbox','repeat'))) {
echo '<li class="'.$type.'">';
echo '<input type="hidden" name="form'.$deep.'['.$i.'][type]" value="'.$type.'"><span></span>';
echo '<input name="form'.$deep.'['.$i.'][name]" value="'.$element['name'].'">';
echo ' | ';
if ($type!='repeat') {
echo '<label for="required'.$id.$i.'"><input type="checkbox" name="form'.$deep.'['.$i.'][required]" id="required'.$id.$i.'"'.(isset($element['required'])&&$element['required']?' checked':'').'> Required</label>';
} else {
echo '<label for="min'.$id.$i.'">Min: <input name="form'.$deep.'['.$i.'][min]" id="min'.$id.$i.'" value="'.(($mi=$element['min'])<=0||!is_int(intval($mi))?'0':intval($mi)).'"></label>';
echo '<label for="max'.$id.$i.'">Max: <input name="form'.$deep.'['.$i.'][max]" id="max'.$id.$i.'" value="'.(($ma=$element['max'])<=0||$ma<$mi||!is_int(intval($ma))?'&infin;':intval($ma)).'"></label>';
}
echo ' | ';
echo '<button type="submit" name="action" value="move up '.$id.$i.'"'.($i==0?' disabled':'').' title="Move up">Up</button>';
echo '<button type="submit" name="action" value="move down '.$id.$i.'"'.($i==count($base)-1?' disabled':'').' title="Move down">Down</button>';
if ($type!='repeat') {
echo ' | ';
echo '<button type="submit" name="action" value="repeat '.$id.$i.'"'.(count($depth)==MAXDEPTH||$type=='repeat'?' disabled':'').' title="Create repeating block">Repeat</button>';
echo '<button type="submit" name="action" value="merge up '.$id.$i.'"'.(!$prev||$type=='repeat'?' disabled':'').' title="Merge with the above repeating block">Merge&nbsp;up</button>';
echo '<button type="submit" name="action" value="out down '.$id.$i.'"'.(!$depth?' disabled':'').' title="Jump out of this repeating block">Jump&nbsp;down</button>';
}
echo ' | <button type="submit" name="action" value="delete '.$id.$i.'" title="Delete this element">Delete</button>';
if ($prev=($type=='repeat')) {
echo '<ul>';
drawList($element['value'],array_add(array_add($depth,$i),'value'));
echo '</ul>';
}
echo '</li>';
}
}
}
?>
<!DOCTYPE html>
<meta charset="utf-8">
<title>Form builder.</title>
<style>
html{text-align:center;}
body{max-width:960px;margin:0 auto;text-align:left;font-family:sans-serif,sansserif;}
*{font-size:100%;}
#form>button{padding:.5em 2em;margin:0 .5em 0 0;}
#formsettings,#form,#error{border:2px solid #FFDDDD;padding:.5em 1em;margin:2em 0;}
#error{border-color:#CD2A2F;padding:0 1em;}
#error ul{list-style:none;margin:0;padding:0;}
#error li{background:transparent url(img/delete.png) left center no-repeat;padding-left:26px;margin:.5em 0;}
#formsettings label{margin:0 1em 0 0;}
#form ul{margin:2em 0;padding:0;list-style:none;}
#form li{margin:5px 0;}
#form li.repeat{background-color:rgba(126,140,66,.1);margin-left:-10px;padding:.2em 0 .2em 10px;border-top:1px solid rgba(106,120,46,.3);}
#form ul ul{padding-left:10px;margin:0;}
#form button,#form label{cursor:pointer;cursor:hand;}
select{margin:0 .5em;padding: 0 2em 0 .5em;}
button[value=new]{margin:0 .5em !important;}
li label{padding:0 .5em;}
li input[type=checkbox]{margin:0 .5em 0 0;}
li button[name=action]{width:32px;height:32px;text-indent:40em;overflow:hidden;border:0;background:transparent center center no-repeat;color:rgba(255,255,255,0);}
li button[value*=" up "]{background-image:url(img/up.png);}
li button[value*=" down "]{background-image:url(img/down.png);}
li button[value^="repeat "]{background-image:url(img/repeat.png);}
li button[value^="delete "]{background-image:url(img/delete.png);}
li button[value^="merge up "]{background-image:url(img/mergeup.png);}
li button[value^="out down "]{background-image:url(img/jumpdown.png);}
button[disabled]{opacity:.3;}
input[name$="[type]"]+span{width:16px;height:16px;border:0;background:transparent center center no-repeat;display:inline-block;margin: 0 .5em -3px 0;}
input[name$="[type]"][value="text"]+span{background-image:url(img/text.png);}
input[name$="[type]"][value="textarea"]+span{background-image:url(img/textarea.png);}
input[name$="[type]"][value="checkbox"]+span{background-image:url(img/checkbox.png);}
input[name$="[type]"][value="repeat"]+span{background-image:url(img/repeat.png);}
input[id^=min],input[id^=max]{width:3em;}
</style>
<form method="post" accept-charset="utf-8">
<?php if (isset($error)&&count($error)) { ?><div id="error">
<ul><?php foreach ($error as $msg) { echo '<li>'.$msg.'</li>'; } ?></ul>
</div><?php } ?>
<div id="formsettings">
<input type="hidden" name="formid" value="<?php echo isset($_POST['formid'])?$_POST['formid']:''; ?>">
<label for="formname">Form name</label> <input name="formname" id="formname" value="<?php echo isset($_POST['formname'])?trim($_POST['formname']):''; ?>"><br>
</div>
<div id="form">
<button type="submit" name="action" value="add text">Text</button>
<button type="submit" name="action" value="add textarea">Textarea</button>
<button type="submit" name="action" value="add checkbox">Checkbox</button>
<ul>
<?php drawList($form); ?>
</ul>
<button type="submit" name="action" value="cancel">Cancel</button>
<button type="submit" name="action" value="save">Save</button>
|
<button type="submit" name="action" value="new">New</button>
|
<select name="formselect">
<?php
$forms = mysql_query("SELECT * FROM db_form_settings") or die(mysql_error());
while($form = mysql_fetch_array($forms)) {
echo '<option value="'.$form[0].'"'.(isset($_POST['formid'])&&$_POST['formid']==$form[0]?' selected':'').'>'.$form[1].'</option>';
}
?>
</select>
<button type="submit" name="action" value="load">Load</button>
<button type="submit" name="action" value="drop">Delete</button>
</div>
</form>
<?php
# ### ### ### ### ### ### ### ### ### ###
# DEBUG
//echo '<pre><h3>Action</h3></pre>',pre_var_dump(isset($action)?$action:null),'<pre><h3>$_POST</h3></pre>',pre_var_dump($_POST),'<pre><h3>$form</h3></pre>',pre_var_dump($form);
# ### ### ### ### ### ### ### ### ### ###
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment