Jump to content

Validating max number of characters in input field


eldan88

Recommended Posts

Hey Guys. I am trying to validate the max numbers of characters in a text field. For example credit card numbers can't be have more than 16 characters and no less then 15 characters.  The Name field can't be more than 30 characters etc etc. 

 

My first question:  Can I some how pass this type of value in the input field, and use that value to preform the checking in php?

 

 

My second question: Should I create if statements for the min/max values I want to validate under the foreach loop? My foreach loop is in the validate_fields method located in the validate.php(Second code block)

 

Or is it better to create another method to check for max/min values?

 

 

Below is my form(form.php)

<?php
include("validation.php");
if(isset($_POST['submit'])) {
    //$name = $_POST['name'];
    //$last_name = $_POST['last_name'];

   // $fields = array($name, $last_name );
     $_POST;
     unset($_POST['submit']);
    $errors = $form_validation->validate_fields($_POST);
   if (count($errors)>0)
  echo implode("<br/>",$errors);
 
}

?>
<!doctype html>
<html>
<head></head>
 
    <body>
        <form action="#" method="POST">

            <input type="text" name="Name" id="name">
            <input type="text" name="last_name" id="last_name">
            <input type="text"  name="credit_card" id="credit_card"
            <input type="submit" value="submit" name="submit">

        </form>
    </body>
</html>

Here is my validation class (validation.php)

<?php

class validation {
	
	public function validate_fields($form_fields="") {
		  $errors = array(); 
            foreach ($form_fields as $key=>$value) {
            	if(empty($value)) {
            		$errors[] = str_replace("_", " ", $key) . " Is empty"; 
            	}// end of if
            
            	
            }// end of foreach
            return $errors; 



	}// end of function


}// end of class

$form_validation = new validation();

?>
Link to comment
Share on other sites

My first question:  Can I some how pass this type of value in the input field, and use that value to preform the checking in php?

You could, for example, include it in the field name as an array index key like so

<inpyt type="text" name="cc[15-16]">

But you absolutely shouldn't. Never trust ANY data coming from the user. Why even validate the input if you are going to pass the logic on how to validate to the user?

 

 

My second question: Should I create if statements for the min/max values I want to validate under the foreach loop? My foreach loop is in the validate_fields method located in the validate.php(Second code block)

 

Or is it better to create another method to check for max/min values?

 

I don't like the look of that class (maybe there is more I am not seeing). I would create the class to have methods for each type of validation that may be done to a field. Then - in the code - I would call each method for the POST values as appropriate. You could create a method that allows you to run multiple validations on a single field so you don't have to call each individually as well.

Link to comment
Share on other sites

Hey Pshyco. You are right. I could validate the logic without passing logic. Didn't think of that.

 

Why don't you like the look of my class? What do you mean by "You could create a method that allows you to run multiple validations on a single field so you don't have to call each individually as well?"

Link to comment
Share on other sites

There are a ton built-in functions and extensions (that are often included standard) for checking string length, some that will return true or false if the string has only numbers or letters or numbers and letters only, etc.. spend a romantic evening with the manual. Here's a few links to get you started:

 

http://www.php.net/manual/en/ref.strings.php

http://www.php.net/manual/en/ref.pcre.php

http://us1.php.net/ctype

http://us1.php.net/mb_string

Link to comment
Share on other sites

Why don't you like the look of my class? What do you mean by "You could create a method that allows you to run multiple validations on a single field so you don't have to call each individually as well?"

 

Too much to try and go into. But, I'll give a few details. It assumes every field is required. That may be the case today, what do you do later when you want to add a non-required field? Well, you would have to hard-code something into the class to specifically skip the require check for the particular field and that completely ruins the portability of the class.

 

Here is a VERY quick and dirty example (not tested). I'm sure this could be greatly improved upon, but should show what I am talking about

class validator
{
    $errors = array();
    $currentValue = false;

    public function __contruct()
    {

    }

    public function validateField($fieldName, $fieldValue, $validations)
    {
        $this->currentValue = $fieldValue;

        //Verify all validation needs for the field
        foreach($validations as $validate => $args)
        {
            switch($validate)
            {
                case 'require':
                    if(!$this->required())
                    {
                        $this->errors[] = "The field {$fieldName} is required.";
                        return false; //No need to do any other validations
                    }
                    break;

                case 'length':
                    if(!$this->length($args))
                    {
                        $this->errors[] = "The field {$fieldName} must be between {$args['min']} and {$args['max']}.";
                        return false; //No need to do any other validations
                    }
                    break;

                case 'email':
                    if(!$this->email())
                    {
                        $this->errors[] = "The field {$fieldName} contain a valid email.";
                        return false; //No need to do any other validations
                    }
                    break;
            }
        }

        //Return true or false based upon whether there were errors
        return (count($error) == 0);
    }

    public function getErrors()
    {
        return $this->errors;
    }

    private function required()
    {
        return (strlen($currentValue) > 0);
    }

    private function length($args)
    {
        $valueLen = strlen($currentValue);
        return ($valueLen >= $args['min'] && $valueLen <= $args['max']);
    }

    private function required()
    {
        //Add code to validate value is in proper email format
    }
}

//Usage
$validator = new validator();
$validator->validateField('Name', $_POST['name'], array('required'=>null, 'length'=>array('min'=>5,'max'=>20));
$validator->validateField('Email', $_POST['email'], array('required'=>null, 'email'=>null);
 
$validationErrors = $validator->getErrors();
if(count($validationErrors))
{
    //display errors
}
else
{
    //Continue
}
 
Edited by Psycho
Link to comment
Share on other sites

Physco. I have a question about your code.

 

  1. Why is there a __construct() method. I know what it does. But I am not sure why its there.
  2. Where can I find the values that would match with the switch statement ... 'require','length' .. I don't see anything that would be assigned to $validate that would match up with these statments.

Thanks!

Link to comment
Share on other sites

Rather than doing a case that way you could get the length in a case statement via

switch (TRUE)
case (isset($_POST['str']) && $str=$_POST['str'] . $length=strlen($str) . $length>=15):
echo "string is 15 char or longer.";
break;
default:
echo "string is shorter than 15 char.";

}

I know it's a little bit different, but it seems to work  with '.' loading for some reason, but I don't know why.

Link to comment
Share on other sites

I know it's a little bit different, but it seems to work  with '.' loading for some reason, but I don't know why.

Never trust someone's advice who says this.

 

Q695 did you even run your code? Do you have all your error reporting turned off? There are all kinds of wrong in that code both logically and syntactically.

Link to comment
Share on other sites

Physco. I have a question about your code.

  • Why is there a __construct() method. I know what it does. But I am not sure why its there.
  • Where can I find the values that would match with the switch statement ... 'require','length' .. I don't see anything that would be assigned to $validate that would match up with these statments.
Thanks!

 

as-is there are a lot of issues with the code psycho posted. He did say it was "quick and dirty and untested". But overall it was meant to show you a better way of doing it: write individual methods for each type of validation. That way you (moreso) de-couple the logic from the data, and de-coupling is one of the major principles of object oriented programming.

Link to comment
Share on other sites

Never trust someone's advice who says this.

 

Q695 did you even run your code? Do you have all your error reporting turned off? There are all kinds of wrong in that code both logically and syntactically.

2.No, I just haven't turned on strict

3.On another file it runs perfectly fine with one '.' in between to load a number in

4.Why wouldn't it create errors in WAMP, but create errors in the PHP server for other hosts?

Link to comment
Share on other sites

 

Too much to try and go into. But, I'll give a few details. It assumes every field is required. That may be the case today, what do you do later when you want to add a non-required field? Well, you would have to hard-code something into the class to specifically skip the require check for the particular field and that completely ruins the portability of the class.

 

Here is a VERY quick and dirty example (not tested). I'm sure this could be greatly improved upon, but should show what I am talking about

class validator
{
    $errors = array();
    $currentValue = false;

    public function __contruct()
    {

    }

    public function validateField($fieldName, $fieldValue, $validations)
    {
        $this->currentValue = $fieldValue;

        //Verify all validation needs for the field
        foreach($validations as $validate => $args)
        {
            switch($validate)
            {
                case 'require':
                    if(!$this->required())
                    {
                        $this->errors[] = "The field {$fieldName} is required.";
                        return false; //No need to do any other validations
                    }
                    break;

                case 'length':
                    if(!$this->length($args))
                    {
                        $this->errors[] = "The field {$fieldName} must be between {$args['min']} and {$args['max']}.";
                        return false; //No need to do any other validations
                    }
                    break;

                case 'email':
                    if(!$this->email())
                    {
                        $this->errors[] = "The field {$fieldName} contain a valid email.";
                        return false; //No need to do any other validations
                    }
                    break;
            }
        }

        //Return true or false based upon whether there were errors
        return (count($error) == 0);
    }

    public function getErrors()
    {
        return $this->errors;
    }

    private function required()
    {
        return (strlen($currentValue) > 0);
    }

    private function length($args)
    {
        $valueLen = strlen($currentValue);
        return ($valueLen >= $args['min'] && $valueLen <= $args['max']);
    }

    private function required()
    {
        //Add code to validate value is in proper email format
    }
}

//Usage
$validator = new validator();
$validator->validateField('Name', $_POST['name'], array('required'=>null, 'length'=>array('min'=>5,'max'=>20));
$validator->validateField('Email', $_POST['email'], array('required'=>null, 'email'=>null);
 
$validationErrors = $validator->getErrors();
if(count($validationErrors))
{
    //display errors
}
else
{
    //Continue
}
 

 

Hey Phsyco. I  understood most of the code even though it was quick and dirty.

 

What I don't understand is why did you put the not operator infron the $this when accessing the methods?? Can you please explain? Thanks!!!

 

For example

 case 'require':
                    if(!$this->required()) // Why is there a !$this
                    {
                        $this->errors[] = "The field {$fieldName} is required.";
                        return false; //No need to do any other validations
                    }
Edited by eldan88
Link to comment
Share on other sites

2.No, I just haven't turned on strict

3.On another file it runs perfectly fine with one '.' in between to load a number in

4.Why wouldn't it create errors in WAMP, but create errors in the PHP server for other hosts?

Really? Because this code right here:

 

<?php
switch (TRUE)
case (isset($_POST['str']) && $str=$_POST['str'] . $length=strlen($str) . $length>=15):
echo "string is 15 char or longer.";
break;
default:
echo "string is shorter than 15 char.";

}
?>
Immediately gives the following error:

 

Parse error: syntax error, unexpected T_CASE, expecting ':' or '{' in test.php on line 3
This isn't a "strict" error. It's a straight up syntax error, showing you are missing an opening bracket.

 

So let's go ahead and fix that and move on and do some test shall we?

 

First, let's use a string longer than 15 chars:

 

<?php
$_POST['str'] = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'; // 39 chars

switch (TRUE) {
case (isset($_POST['str']) && $str=$_POST['str'] . $length=strlen($str) . $length>=15):
echo "string is 15 char or longer.";
break;
default:
echo "string is shorter than 15 char.";

}
?>
Output:

string is 15 char or longer.
Okay, working good so far... or is it..... let's try something less than 15 chars:

 

<?php
$_POST['str'] = 'aaaaa'; // 5 chars

switch (TRUE) {
case (isset($_POST['str']) && $str=$_POST['str'] . $length=strlen($str) . $length>=15):
echo "string is 15 char or longer.";
break;
default:
echo "string is shorter than 15 char.";

}
?>
Output:

string is 15 char or longer.
Wait, what?? Why would it do that?!?!? Q695 I would explain why, but you already "burst my bubble" so why don't you explain why this doesn't work. Oh, right. You can't, because you think it's working. You don't know wtf it's doing, just like you said you didn't know wtf it's doing right here. I'm sorry to be harsh, but you know.. maybe you shouldn't be so quick to PM someone making snide remarks, especially when out of your own mouth you admit you don't know what's going on.
Link to comment
Share on other sites

@eldan88: psycho's missing and inaccurate code is because it was a "quick and dirty, untested" example, just like he said it was. Basically there are typos and half-fleshed out ideas, which is to be expected from a quick and dirty, untested example. It was meant to be pseudo-code to give you a general idea about how you can structure your stuff in general. You're missing the forest for the trees, as the saying goes.
Link to comment
Share on other sites

If you're using a switch statement you should know how to debug it if someone helping you forgets a {.  Was the Psudo code correct?

 

Why does the "." allow you to put more instructions between an and when testing the TRUE of a statement?

Link to comment
Share on other sites

I understand that the missing bracket was a typo. But when you say something works, then no, you don't get a free pass on expecting people to treat it as pseudo-code.  Saying something works implies that you actually tested it and it should work.  Can someone easily pick that error out and fix it? Sure.  But I was nonetheless being pedantic because you were being an asshat via PM.

 

But that missing bracket isn't really the point.  The point is that you don't understand what your code is doing and yet you are arguing that it works for some unknown reason, when it fact it doesn't. 

 

"." does not allow you to put more instructions between an && when testing the TRUE of a statement.  That is not what is happening at all.  A dot is a concatenation operator; it joins strings together. Then you have several variable assignments going on which isn't going to work as you expect because of operator precedence.  This is where things get really confusing, and honestly I don't fault you at all for not understanding wtf is going on.. it took me a good while to sort it out myself.  What I do fault you is for not properly testing the code and passing it off saying it works, despite admitting you don't know what it's doing. Even if you don't know what's going on, you could have easily tested the code and seen that it doesn't work as expected, by doing exactly what I did in my last post.

 

So here is what is happening.

 

First, isset($_POST['str']) is evaluated, and (presumably) evaluates as true (which it does in my example where I just hardcode it to a value instead of receive a form input).

 

Then, with this:

 

$str=$_POST['str'] . $length=strlen($str) . $length>=15
What really happens is everything on the right side of that first equal sign is evaluated and assigned to $str and if that overall value works out to a truthy value, then overall we have an equivalent of if (true && true). Why does it work out this way? The key is the 2nd example note in the Operator Precedence entry that states even though the assignment operator has lower precedence than most other stuff, you can still use it within a condition to make the condition evaluate the value assigned to the variable. This practically flips order of operations, making the equal sign one of the highest in precedence.

 

So, let's examine whether or not we get a truthy value from the rest of that stuff:

 

$_POST['str'] . $length=strlen($str) . $length>=15
$_POST['str'] will have an actual value, whatever the user entered in the form. The same value evaluated in the first isset call. In my example I used a long string "aaa...". For this example I'm just going to assume it's "foobar" for the sake of space. So, so far we have "foobar" as the value being assigned to $str. At this point in time, it really doesn't matter what comes next. Even if everything else returns false or some other value, overall you have a truthy value. But let's be thorough and finish this exercise so that you may fully understand what is going on.

 

Next, we have a concatenation operator, which means we're going to start gluing shit to the end of "foobar" to make a longer string.

 

$length=strlen($str) is same concept as before.. we're going to evaluate strlen($str). Which is null because at this point, $str doesn't actually exist yet, and trying to pass nothing to strlen gives you null, and a Notice. So, if you had error reporting on, this would have been your first clue that something is amiss; you should have gotten something like this:

 

Notice: Undefined variable: str in test.php on line 8
This is a Notice level error. You claim that you have all error reporting turned on except strict. So you should have seen this. Which means your error reporting settings aren't what you think it is, or else you just lied on that count. Anyways.. since this returns false, we're still sitting with "foobar" as what's ultimately going to be assigned to $str.

 

So now we have $length=null.$length>=15. Firstly, we're actually still assigning things to $length at this point, since you have another concatenation operator between this and the last thing. So $length isn't defined at this point, so you should have received a 2nd notice:

 

Notice: Undefined variable: length in test.php on line 8
So null.undefined is undefined, and then undefined>=15 is false, so overall, $length=false. Then that gets concatenated onto "foobar", so overall we now have...

 

$y="foobar".false
...which effectively makes nothing get concatenated to it and thus we effectively have $str="foobar" as the 2nd expression being evaluated in the case. And since "foobar" is a truthy value, the overall condition is true.

 

So IOW:

 

$_POST['str']='foobar';
if (isset($_POST['str']) && $str=$_POST['str'] . $length=strlen($str) . $length>=15)
if (isset('foobar') && $str=$_POST['str'] . $length=strlen($str) . $length>=15)
if (true && $str=$_POST['str'] . $length=strlen($str) . $length>=15)
if (true && $str='foobar' . $length=strlen($str) . $length>=15)
if (true && $str='foobar' . $length=strlen(undefined) . $length>=15)
if (true && $str='foobar' . $length=null . $length>=15)
if (true && $str='foobar' . $length=null . undefined>=15)
if (true && $str='foobar' . $length=undefined>=15)
if (true && $str='foobar' . $length=false)
if (true && $str='foobar' . false)
if (true && 'foobar')
if (true && true)
if (true)
Now, I hope you learned something here today. Firstly, don't just pawn something off as an answer when you don't understand what it's doing. Second, don't be a jackass about it, especially when you admit you don't understand what it's doing. But thirdly more important, I hope you now more fully understand the code and why it's wrong.
Link to comment
Share on other sites

I was basing it off this logic working, never actually tested it by writing it out, because I thought it was some big new discovery, because "&&" doesn't work, but "." does.

isset($_GET['____']) && $i=$_GET['____'] . is_int($i)
Link to comment
Share on other sites

I was basing it off this logic working, never actually tested it by writing it out, because I thought it was some big new discovery, because "&&" doesn't work, but "." does.

isset($_GET['____']) && $i=$_GET['____'] . is_int($i)

 

Okay well FYI, this code doesn't work as expected either. Run the following:

 

ini_set('display_startup_errors',1);
ini_set('display_errors',1);
error_reporting(-1);

echo '<b>test1: 0<br/>';
$_GET['____']=0;
if ( isset($_GET['____']) && $i=$_GET['____'] . is_int($i) ) 
  echo 'true';
else 
  echo 'false';
  
echo '<br/>';
echo 'i is: ';var_dump($i);
echo '<br/><br/>';
unset($i);

echo '<b>test2: 5<br/>';
$_GET['____']=5;
if ( isset($_GET['____']) && $i=$_GET['____'] . is_int($i) ) 
  echo 'true';
else 
  echo 'false';
  
echo '<br/>';
echo 'i is: ';var_dump($i);
echo '<br/><br/>';
unset($i);

echo '<b>test3: foobar<br/>';
$_GET['____']='foobar';
if ( isset($_GET['____']) && $i=$_GET['____'] . is_int($i) ) 
  echo 'true';
else 
  echo 'false';
  
echo '<br/>';
echo 'i is: ';var_dump($i);
echo '<br/><br/>';
Output:

 

test1: 0

Notice: Undefined variable: i in /home/crayonvi/public_html/test.php on line 8
false
i is: string(1) "0" 

test2: 5

Notice: Undefined variable: i in /home/crayonvi/public_html/test.php on line 20
true
i is: string(1) "5" 

test3: foobar

Notice: Undefined variable: i in /home/crayonvi/public_html/test.php on line 32
true
i is: string(6) "foobar" 
With error reporting turned on, you can see you're getting the same Notice. It's coming from is_int($i) being evaluated when $i doesn't actually exist yet.

 

Then you can see that you are getting a false negative on test 1 because 0 is being evaluated as a falsey value, even though it's legitimately an integer. Then in the 2nd one, it's getting true but not for the reason you think. It's getting true because overall $i=5.false evaluates true. This "conveniently" works out for you in this scenario, but as you can see it didn't work out in the first scenario. Well maybe you don't care about 0. So let's move on to the non-integer example #3.

 

In #3 it's doing the same thing as before, where overall $i='foobar'.false == $i='foobar' == true.

 

So IOW, as long as you path a truthy value to $_GET['____'], regardless of whether it's an integer, string, object, sql or xss injection code, etc.. anything that evaluates true..

Link to comment
Share on other sites

$i gets loaded when the first case statement is true, but when the $_GET is false it sees no need to load $i, thus false  when I put _______ you can pass any variable into the field that you want.

 

I know the code works in my case statement, but I don't know exactly why it lets you pass the variable in, then run the check.

Edited by Q695
Link to comment
Share on other sites

$i gets loaded when the first case statement is true, but when the $_GET is false it sees no need to load $i, thus false  when I put _______ you can pass any variable into the field that you want.

$i gets defined eventually yes, but not before you try and use it, which is why the notice error appears and why the code ultimately fails. What you have, if expanded out into a more verbose code is:

//isset($_GET['____']) && $i=$_GET['____'] . is_int($i)
if (isset($_GET['____'])){
   $tmp = $_GET['____'];
   $tmp = $tmp . is_int($i);
   $i = $tmp;
   if ($i){
      //Something
   }
}
The code is wrong, as one can obviously see from the expanded out version. If you want to check is_int($i) after $i is assigned you would write:

isset($_GET['____']) && ($i=$_GET['____']) && is_int($i)
Link to comment
Share on other sites

.josh. Thanks for the reply. I am still not sure why he would put the construct method even if it was quick and dirty. I don't see anything to automatically construct..

 

Because I always start a class with a construct method - even if it is empty. I don't know if I was going to need it or not. In fact, I think I may have had some code in it while I was throwing that example together and may have ended up removing it. It's just one of the practices I follow when coding.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.