Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Stuck with my own code :( 1

Status
Not open for further replies.

Sleidia

Technical User
May 4, 2001
1,284
FR
Hello everyone :)

I've written a function for form validation but I can't find a way to make it work with fields that are arrays.
I know it's pretty lame to ask for help on a quite big function that I've written on my own with my own weird logic but you guys are the only ones who could help me or at least, give ideas.

Many thanks to those who will help :)

Code:
// my function works with such field names
<input type="text" name="form_val" value="1" /> value 1

// my function doesn't work with such field names
<input type="checkbox" name="form_val[]" value="1" /> value 1
<input type="checkbox" name="form_val[]" value="2" /> value 2
<input type="checkbox" name="form_val[]" value="3" /> value 3

or

<input type="checkbox" name="form_val[11][]" value="1" /> value 1
<input type="checkbox" name="form_val[11][]" value="2" /> value 2
<input type="checkbox" name="form_val[11][]" value="3" /> value 3

or 

<input type="checkbox" name="form_val[22][]" value="1" /> value 1
<input type="checkbox" name="form_val[22][]" value="2" /> value 2
<input type="checkbox" name="form_val[22][]" value="3" /> value 3

Ok, here is my function that I would like to enhance :

Code:
//  SHOW ERRORS
// ---------------------------------------------------------------------------

function show_errors($one_form, $one_title, $one_name, $one_message) {

static $field_names = "";
global $set_forms_config;

    if($_POST OR $_FILES) $postarray = array_merge($_POST, $_FILES);
		
    // display form
		if($one_title != NULL AND $one_name != NULL) {
		
		$GLOBALS['curfieldname'] = $one_name;
		static $title_num = 0;

		// format of default title
		$title_bef = "<span class=\"form-title-error\">";
		$title_aft = "</span>";	
						
				// if values submitted	
				if($_POST["form_name"] == $one_form) {
				
						if($postarray[$one_name] == "" OR strstr($field_names, $one_name)) {
						
						static $error_num = 1;
						
						// format title when error
						$title_bef = "<a name=\"" . $one_name . "\"><span class=\"form-title-error\">";
						$title_aft = "</span></a>";	
						
                if ($field_names == "") $title_bef_num = "<b>[ " . $error_num . " ]</b> ";
						
            $one_title = $title_bef_num . $one_title;
						$error_num++;
												
						} else {						
						
						// format title when ok
						$title_bef = "<span class=\"form-title-ok\">";
						$title_aft = "</span>";	
						
						}				

        // on very first sight		
				} else {

				$_SESSION["hd_forms"][$one_form]["field_title"][] = $one_title;
				$_SESSION["hd_forms"][$one_form]["field_name"][] = $one_name;
				
				}
				
		return $title_bef . $one_title . $title_aft;
							
		// show empty fields
		} else if($one_title == NULL AND $one_name == NULL) {
						
				for($i=0; $i < sizeof($_SESSION["hd_forms"][$one_form]["field_name"]); $i++ ) {									
        
        $temp_name = $_SESSION["hd_forms"][$one_form]["field_name"][$i];
        
            // - ! - if field for array
            if (strstr($temp_name, "]")) {


            // - ! - if field not for array
            } else {
            
            $temp_val = $postarray[$temp_val];
            
            }
        
						if($temp_val == "") {
            
						$GLOBALS['errors'] .= "
            <b>
            " . str_replace("}_{", " 
            <a href=\"javascript: 
            document.location.href='#" . $_SESSION["hd_forms"][$one_form]["field_name"][$i] . "';
            document." . $postarray["form_name"] . "." . $_SESSION["hd_forms"][$one_form]["field_name"][$i] . ".className += ' form-field-error'; 
            document." . $postarray["form_name"] . "." . $_SESSION["hd_forms"][$one_form]["field_name"][$i] . ".focus();\" 
            onMouseOver=\"status='" . addslashes($_SESSION["hd_forms"][$one_form]["field_title"][$i]) . "';return true\" 
            class=\"form-title-error\">
            [ " . ($error_num + 1) . " ]
            " . $_SESSION["hd_forms"][$one_form]["field_title"][$i] . "
            </a> 
            ", hd_page_textfill(1)) . "
            </b><br>\n
            ";
						
            $error_num++;
						
						} else {								
						
						}
						
				}
		
		} else {
		
		// specific detection
				if(!$error_num) static $error_num = 1;
				
				$temp_array = explode(" . ", $one_name);
				$one_name = $temp_array[0];
				
						for($i=0; $i < sizeof($temp_array); $i++ ) {
						
            $field_names .= $temp_array[$i] . " . ";
    				
            $js_link .= "
            document." . $postarray["form_name"] . "." . $temp_array[$i] . ".className += ' form-field-error'; 
            document." . $postarray["form_name"] . "." . $temp_array[$i] . ".focus();
            ";
						
						}

				$GLOBALS['errors'] .= "
        <a href=\"javascript: " . $js_link . "\" 
        onMouseOver=\"status='';return true\" 
        class=\"form-title-error\">
        [ " . $error_num . " ] 
        " . $one_message . "
        </a>
        <br>\n
        ";

				$error_num++;
		
		return $GLOBALS['errors'];
		
		}

}

// ---------------------------------------------------------------------------

//  RESET

// ---------------------------------------------------------------------------

    if(!$_POST) {
    
    unset($_SESSION["hd_forms"]);
    
    }

Here is how the function is called :

Code:
// Call upon form display

...
<tr>
<td>" . show_errors($form_name, "Product Reference", "form_prod_ref", NULL) . "<br />
<input type=\"text\" name=\"" . $curfieldname . "\" value=\"" . $_POST[$curfieldname] . "\" class=\"field1\" maxlength=\"33\" /></td>
</tr>

<tr>
<td>" . show_errors($form_name, "Product Name", "form_prod_name", NULL) . "<br />
<input type=\"text\" name=\"" . $curfieldname . "\" value=\"" . $_POST[$curfieldname] . "\" class=\"field1\" maxlength=\"33\" /></td>
</tr>
...

Code:
// Call upon form validation

// - ! - find empty fields
show_errors($_POST["form_name"], NULL, NULL, NULL);

// - ! - if no empty fields => start specific detection

    if (!$errors) {
    
    if(strlen($_POST[""form_prod_ref""]) > 10) show_errors($_POST["form_name"], NULL, ""form_prod_ref"", "!This field must not contain more than 10 characters!");
    
    }

    if (!$errors) {
    
    
    // - ! - continue script....
    
    }
 
can we step back from the code a minute? when you mean "validate" what do you want to achieve in re a checkbox? I'm also not sure about the wisdom of trying to handle fields called $field[] and $field[22][] dynamically. one is a subset of another. of course it can work but i would think that you need to provide a form schema to the function first.
 
Hi Jpadie :)

Well, the function does a 2-steps validation on the targeted form elements (the mandatory fields) :

1) find empty/unchecked/unselected elements and display appropriate error message.
Code:
show_errors($_POST["form_name"], NULL, NULL, NULL);
2) apply specific data verification on specific fields and dislpay appropriate error message.
Code:
if(strlen($_POST[""form_prod_ref""]) > 10) show_errors($_POST["form_name"], NULL, ""form_prod_ref"", "!This field must not contain more than 10 characters!");

Here is a form sample :

Code:
<input type="text" name="form_elem_a" value="1" /> value 1

<input type="checkbox" name="form_elem_b[]" value="1" /> value 1
<input type="checkbox" name="form_elem_b[]" value="2" /> value 2
<input type="checkbox" name="form_elem_b[]" value="3" /> value 3

<input type="checkbox" name="form_elem_c[11][]" value="1" /> value 1
<input type="checkbox" name="form_elem_c[11][]" value="2" /> value 2
<input type="checkbox" name="form_elem_c[22][]" value="1" /> value 1
<input type="checkbox" name="form_elem_c[22][]" value="2" /> value 2

So, I need my generic function above to check whether
$_POST["form_elem_a"] // normal value
$_POST["form_elem_b"] // normal array
$_POST["form_elem_c"][11] // sub-array of multidim array
$_POST["form_elem_c"][22] // sub-array of multidim array
is empty.

As you can see, it's important that I can check sub-arrays separately as well.

The PHP code for this form would be this :

Code:
echo"

...

<b>" . show_errors($form_name, "Product Reference", "form_elem_a", NULL) . "</b><br />
<input type=\"text\" name=\"form_elem_a\" value=\"1\"/>

<br />
<br />

<b>" . show_errors($form_name, "Product Size", "form_elem_b[]", NULL) . "</b><br />
<input type=\"checkbox\" name=\"form_elem_b[]\" value=\"1\"/>
<input type=\"checkbox\" name=\"form_elem_b[]\" value=\"2\"/>
<input type=\"checkbox\" name=\"form_elem_b[]\" value=\"3\"/>

<br />
<br />

<b>" . show_errors($form_name, "Product Type", "form_elem_c[11]", NULL) . "</b><br />
<input type=\"checkbox\" name=\"form_elem_c[11][]\" value=\"1\"/>
<input type=\"checkbox\" name=\"form_elem_c[11][]\" value=\"2\"/>

<br />
<br />

<b>" . show_errors($form_name, "Product Sub-type", "form_elem_c[22]", NULL) . "</b><br />
<input type=\"checkbox\" name=\"form_elem_c[22][]\" value=\"1\"/>
<input type=\"checkbox\" name=\"form_elem_c[22][]\" value=\"2\"/>

<br />
<br />

...

";

Thanks again :)
 
i will have a look at your code a bit later. in the meantime have you ever taken a look at html_quickform?
 
Thanks for the info Jpadie :)

Unfortunately ( or fortunately? ), I hate to use third party code that I don't fully understand.

I need to understand how my code works in order to have more control. It doesn't prevent me from getting stuck from time to time, but I believe it would be worse if I did the stupid copy/paste thing.

Good night ;)
 
you don't need to use html_quickform to be able to benefit from its architecture. just looking at how it is put together and used will help you structure a better form validation system.

quickform works through a schema. For every form you build:

1. a set of controls and labels
2. a set of rules applying to the form
3. a set of rules applying to each control (which are representatively validated both server and client side at the option of the owner)
4. a set of rules to filter the results
5. a set of rules to process the submission.

once the schema is created a form can be displayed or processed very simply.

in your validation system above (which I guess it supposed to be a library function that can be used for multiple forms), I see no way to tell the show_error() function what the field type is, what the permitted values are etc. and since checkboxes do not submit when unchecked ...


btw for fields in an array like a checkbox i prefer to use in_array than strstr.
 
in your validation system above (which I guess it supposed to be a library function that can be used for multiple forms),..

You're supposing right :)

... I see no way to tell the show_error() function what the field type is, ...

Why would the function need to know what type is each field anyway? I mean, in the hundreds of forms I've designed, I only needed to know whether a form value was a string or an array. I don't see the point to make the difference between several field types when, in the end, there are only two variable types produced by the form (string and arrays).

... and since checkboxes do not submit when unchecked ...

That's why I use the field name. Logically, with the use of field names you're supposed to check whether or not checkboxes have been submitted.

btw for fields in an array like a checkbox i prefer to use in_array than strstr.

I did this exactly because the array doesn't exist if the checkboxes aren't checked.

Anyway, I've managed to highlight/clarify the part that bothers me in the code :

Code:
...
for($i=0; $i < sizeof($_SESSION["hd_forms"][$one_form]["field_name"]); $i++ ) {									

$temp_name = $_SESSION["hd_forms"][$one_form]["field_name"][$i];

    // - ! - if field for array variable
    if (is_array($postarray[$temp_name])) {

        // - ! - if sub-array to check. ie : $_POST["form_elem"][x]
        if (strstr($temp_name, "]")) {
        
            /* 
            here is where the difficulty lies : I  have to find out if 
            $_POST["form_elem"][x] is an array by using $temp_name ( ie: form_elem[x] ). 
            */
            if (is_array(??????)) $temp_val = something;
        
        // - ! - if basic array to check. ie : $_POST["form_elem"]
        } else {
        
        $temp_val = $postarray[$temp_name];
        
        }
    
    // - ! - if field for string variable
    } else {
    
    $temp_val = $postarray[$temp_name];
    
    }

		if($temp_val == "") {
...
 
I did this exactly because the array doesn't exist if the checkboxes aren't checked.
that's why in_array is useful and why you might want to consider a schema. Consider this (not bug-tested)

Code:
$fields[] = array(	"fieldname"=>"somecheckbox",
					"fieldtype"=>"checkbox",
					"defaultvalue"=>true,
					"fieldlabel"=>"Tick to confirm acceptance",
					"required"=>"true",
					"errormessage"=>"You must accept the t's and c's",
					"permittedvalues"=>"1";
				);
$errors = array();

if ($_POST['submit']):
	if (validate($fields, "post")):
		//process the form
	else:
		displayform($fields, "post");
	endif;	
else:
	displayform($fields, "post");
endif;

function validate($fields, $type){
	global $errors;
	$errors = array();
	foreach ($fields as $field):
		switch ($field['fieldtype']):
			case "checkbox":
				if ($field['required'] === TRUE):
					$t = "_".strtoupper($type);
					if (!in_array($field['fieldname'], $$t)):
						//not there and it should be ...
						$errors[$fieldname] = $field['errormessage'];
					else:
						$errors[$fieldname] = "";
					endif;
				else:
					$errors[$fieldname] = "";
				endif;
			break;
		endswitch;
	endforeach;
	if (empty($errors)):
		return true;
	else:
		return false;
	endif;
}
function display($fields, $type){
	
	global $errors;
	
	$form = <<<FORM
	<form action="{$_SERVER['PHP_SELF']}" method="$type">
	<table>
	@@@@
	<tr><td>&nbsp;</td><td><input type="submit" name="submit" value="Submit"/></td></tr>
	</table>
	</form>
FORM;
	//highly simplified control renderer
	$controls = "";
	foreach($fields as $field):
		$fieldname=$field['fieldname'];
		$tmp = "";
		$r = $field['required'] ? "<span style=\"color:red;\">*</span>" : "";
		switch ($field['fieldtype']):
			case "checkbox":
				$checked = $field['default'] ? 'checked="checked"' : "";
				$tmp.= <<<CONTROL
	<tr>
		<td>
			{$field['fieldlabel']}$r
		</td>
		<td>
			<input name="$fieldname" type="checkbox" $checked /> {$errors[$fieldname]} />
		</td>
	</tr>
CONTROL;
				$controls .= $tmp;
			break;
		endswitch;
	endforeach;
	$form = str_replace("@@@@", $controls, $form);
	echo $form;
}
 

Thanks a lot for your time, Jpadie :)

Well, this being said, here are the two reasons why I couldn't make any useful use of your code :

1) I don't understand 90% of it ;)
2) Since, as you guessed, my function is already used for plenty of already developped forms, I can't affort rewriting it from scratch. My function already works nicely on strings and simple arrays ( ie: multi select menu, checkboxes ). What I just want to do is to make the function manage multi-dimensional arrays as well. Sorry for being so stubborn ;)

Anyway, I thanks again for the help.

Still, I hope that someone will provide a solution that fits in my existing function.


 
the problem is that your function is difficult to follow without knowing what you're doing with all the session vars and the $one_... etc. and by the time you've explained it all we end up with a larger code chunk than most of us have time to process.

the code that i posted was kept deliberately simple in order to exemplify the use of a schema to do your form generation and validation. that being said ... i understand that you want help with your code.

can you take a step back again, and explain slowly (without reference to your code, but perhaps with reference to a very simple example) what you want to achieve? From what i can guess at, if you have written the code and you can't work out how easily to extend it then you have a design issue!
 
What I just want to do is to make the function manage multi-dimensional arrays as well. Sorry for being so stubborn ;)
at a simple level multi-dimensionality should be handled with a recursive function. however you need to decide on the business rules: does the function return false if any dimension at any level is empty etc. ideally instead you would know up front what array elements you wanted to check and just feed them to a simple function.

can you provide an example of why you might need to test a flat array and a multi-dimensional array?
 
Isn't it time to sleep??? ahaha :)

From what i can guess at, if you have written the code and you can't work out how easily to extend it then you have a design issue!

No, it's not a design issue.
It's only that I don't have a sufficient knowledge to make it work. I'm convinced that a better programmer than me could make it work in its current design.

the problem is that your function is difficult to follow without knowing what you're doing with all the session vars and the $one_... etc. and by the time you've explained it all we end up with a larger code chunk than most of us have time to process.

Hmmm ... the session var $_SESSION["hd_forms"] is simply an array containing the names and labels of all the form elements. This array is populated when the form is displayed on the page for the first time.

So, everytime the form is submitted, the function first searches for empty fields. If $temp_val == "" for a specific form element ( which means that it's neither an array nor a string ) then :
- an error message is added to the string $errors.
- the color of the field label is changed.

But when the field name is form_elem[11] for example, I don't know how to verify that $_POST["form_elem"][11] really exists. The trick is that we have to check its existence with the use of the field name only.

An ugly method would be to do a string manipulation on the field name. In form_elem[11], we could split the field name and the key index, resulting in :
$field_name = "form_elem";
$key_index = 11;

And then, do a
if(is_array($_POST[$field_name][$key_index])) $temp_val = $_POST[$field_name][$key_index];

That's the only solution I've found with my limited knowledge but I find it quite ugly, really.
 
Just an update to let you know that I've finally used the string manipulation method and that the function now works as intended.

Here are the changes I've made :

Code:
for($i=0; $i < sizeof($_SESSION["hd_forms"][$one_form]["field_name"]); $i++ ) {									
      
      $temp_name = $_SESSION["hd_forms"][$one_form]["field_name"][$i];
      $temp_val = "";
      
          // - ! - if sub-array to check. ie : $_POST["form_elem"][x]
          if (strstr($temp_name, "]")) {

          $temp_elem = str_replace(strstr($temp_name, "["), "", $temp_name);
          $temp_key = trim(strtr(str_replace($temp_elem, "", $temp_name), "[]", "  "));
              
              if (is_array($postarray[$temp_elem][$temp_key])) $temp_val = $postarray[$temp_elem][$temp_key];

          // - ! - if field for simple array or sting
          } else {
          
          $temp_val = $postarray[$temp_name];    
          
          }          
      
					if($temp_val == "") {
          
					$GLOBALS['errors'] .= "

Again, I would like to thank you for always being around.

Merci :)
 
de rien!

for what it's worth, it looks to me as though you are partially using a schema but you are building it fresh each time and storing it in the session variable.

Do give some thought to altering the process a bit - create the schema first and then use it to build the form, validate the data and process it. you could easily write your own scheme with very basic coding skills and i'm sure an old-hack like yourself could do so pretty quickly. but i would also very highly recomment html_quickform. it's very well supported and maintained and an absolutely excellent form abstraction layer. i use it for pretty much all my data-driven applications.
 

Hmmm ... I'm afraid that, with a schema, I would lack the freedom I have in term of design. I want to be able to place the form elements wherever I want in the layout without any restriction. Even if it's not the case, I bet there must be some limitation.

I mean, it's good to have generic/omnipotent functions but when it's too omnipotent, you're bound to give up a certain level of freedom.

In the end, you end up with doing exactly the same thing others do, and I don't like it. I know that the way I code is very crude (it's not even OOP) but I refuse to be the slave of the Matrix ahaha :)

 
i don't think OOP is more advanced vs procedural code. they are just different ways of doing the same thing. OOP has the advantage of being encapsulated and this can be useful. Very little of what I produce requires OOP and most of my apps are written in normal procedural code.

schemas do not necessarily limit you although there are certain trade offs with html_quickform between abstraction and flexibility these are very minor. you can display controls anyway that you like with custom renderers or even not use quickform to display the form at all - just use it for the very strong validation rules it provides.

my advice is not to dismiss it until you have tried it. there is a learning curve, but it is shallow and the benefits are very considerable (imho).
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top