0

I want to check whether is my string following this rules?

  • at least 6 characters
  • maximum 40 characters
  • it's containing both digits and letters

I think I have to use look ahead. So here is what I've tried so far:

if ( preg_match( $string, "/^((?!=[0-9]{1,})(?!=[a-zA-Z]{1,})){6,40}$/") ) {
    // following
} else {
    // not following
}

But my pattern doesn't work correctly. How can I fix it?

Martin AJ
  • 6,261
  • 8
  • 53
  • 111
  • Why are you using a negative lookahead? – Anshul Rai Jul 19 '16 at 03:59
  • @AnshulRai Neither won't work .. *negative/positive lookahead* – Martin AJ Jul 19 '16 at 04:01
  • Your `preg_match` is inverted, regex should be first. Is this for password validation? – chris85 Jul 19 '16 at 04:19
  • @chris85 You are right, it is inverted. Also yes, that's for password validation. [here](http://stackoverflow.com/questions/38448115/how-can-i-validate-a-password-based-on-my-rules) is my original question. – Martin AJ Jul 19 '16 at 04:21
  • Does it contain only letters and digits? Or should it contain letters and digits? – Progrock Jul 19 '16 at 04:23
  • @Progrock It can be containing any signs like `$`, `%`, `#` .. I don't care about the other characters. I just have those three rules. – Martin AJ Jul 19 '16 at 04:26
  • I would rethink your approach. Limiting passwords isn't the best approach, http://jayblanchard.net/security_fail_passwords.html and/or https://xkcd.com/936/ – chris85 Jul 19 '16 at 04:26
  • @chris85 *"Limiting passwords isn't the best approach"*. Wrong .. The most of website's users aren't familiar with the concept of security. And usually they choose a weak password. So we have to force them to choose a good password. That's our duty *(as a programmer)* – Martin AJ Jul 19 '16 at 04:28
  • @MartinAJ How many examples of insecure passwords would you like to show that your restrictions aren't requiring a secure passwords? `asdf1234` , `asd123`, `password1`, `passw0rd` – chris85 Jul 19 '16 at 04:30
  • @chris85 Hah .. my restrictions just make it better than `1234`. they don't make a perfect password. – Martin AJ Jul 19 '16 at 04:31
  • 1
    @MartinAJ What's the argument for having a maximum password length? Surely it can't be to increase security. – user94559 Jul 19 '16 at 04:31
  • So just require a minimum length, and make it higher than 6. – chris85 Jul 19 '16 at 04:32

5 Answers5

2

Why build a complicated regular expression when you can just test for the conditions you want?

function isValid($string) {
    return strlen($string) >= 6 &&
           strlen($string) <= 40 &&
           preg_match("/\d/", $string) &&
           preg_match("/[a-zA-Z]/", $string);
}

// Negative test cases
assert(!isValid("hello"));
assert(!isValid("2shrt"));
assert(!isValid("This one is way 2 long! This one is way 2 long! This one is way 2 long!"));
assert(!isValid("abcdef"));
assert(!isValid("123456"));

// Positive test cases
assert(isValid("abcde2"));
assert(isValid("12345a"));
user94559
  • 59,196
  • 6
  • 103
  • 103
1

You may not actually need as much regex for this, it may be overcomplicating it.

I would give this a try:

if(strlen($string) >= 6 && strlen($string) <= 40 && preg_match("/[a-z]/i", $string) && preg_match("/[0-9]/", $string)) {
    //Matches rules
else {
    //Doesn't match
}
ComputerLocus
  • 3,448
  • 10
  • 47
  • 96
1

if you don't care what's in the match and if you just want to check for the conditions...you could try this

^(?=)([0-9]|[a-zA-Z]){6,40}$

^ - starting with
?= - followed by
{6,40} - length
$ - end

EDIT: With regards to the comments here's the modified regex:

^(?=.*[0-9])(?=.*[a-zA-Z])([a-zA-Z0-9]){6,40}$

Explanation:

`?=` Positive Lookahead match any character followed by 0-9 OR
`?=` Positive Lookahead match any character followed by a-z or A-Z
`([a-zA-Z0-9])` Followed by anything in numbers or letters
`{6,40}` length between 6,40

EDIT 2

After further comments this regex should match:

^(?=.*[0-9])(?=.*[a-zA-Z])(.*){6,40}$ anything like !a1234! or -aquy67!

Nishanth Matha
  • 5,993
  • 2
  • 19
  • 28
1

Honestly the best way to deal with this in PHP is not to use a Regular Expression. PHP has a series of "ctype" methods (docs here) built in to the language to allow you to determine character types, and these methods are much easier to use for something like this than Regex. Don't get me wrong Regex is a great and powerful tool, but it's way too much complexity for this problem. Even if you need to extend my solution below with regex for complex pattern matching later on, you can just add it / them for the specific needs you have and you will not have to use it to determine character types.

I would seriously recommend that you write a series of very small functions / methods that you can then compose together to check that the string you are validating passes all of the criteria, like this (you can paste the example into a file and run it on the command-line to see the output from the script below the class definition):

<?php

/* Example written assuming that these methods are all
 * part of a Class, hence the access declarations etc.
 * If you want to write them as a function library that
 * would work fine too
 */

class InputValidation {

    const MIN_LENGTH = 6;
    const MAX_LENGTH = 40;

    public function isLongerThanMinLength($text) {
        $len = strlen($text);
        if ($len > self::MIN_LENGTH) {
            return TRUE;
        } else {
            return FALSE;
        }
    }

    public function isShorterThanMaxLength($text) {
        $len = strlen($text);
        if ($len <= self::MAX_LENGTH) {
            return TRUE;
        } else {
            return FALSE;
        }
    }

    public function hasAlphaAndDigitChars($text) {
        if (ctype_alpha($text) || ctype_digit($text)) {
            return FALSE;
        } else {
            if (ctype_alnum($text)) {
                return TRUE;
            } else {
                return FALSE;
            }
        }
    }

    public function validInput($text) {
        if (!$this->isLongerThanMinLength($text)) {
            return FALSE;
        }
        if (!$this->isShorterThanMaxLength($text)) {
            return FALSE;
        }
        if (!$this->hasAlphaAndDigitChars($text)) {
            return FALSE;
        }
        return TRUE;
    }
}

$inst = new InputValidation;

$test1 = "Hello"; // too short
$test2 = "pneumonoultramicroscopicsilicovolcanoconiosis"; // too long
$test3 = "pneumonoultramicroscopicsil1covolcanocon"; // right length and includes at least one number
$test4 = "123456789123456789"; // right length, but no alphabet chars
$test5 = "HelloMyName"; // right length, but no numeric chars
$test6 = "Hello My Name"; // right length, but has whitespace
$test7 = "Hello^My%Name1"; // right length, but has 'special' chars

print "\n";
var_dump($inst->validInput($test1));
print "\n";
var_dump($inst->validInput($test2));
print "\n";
var_dump($inst->validInput($test3));
print "\n";
var_dump($inst->validInput($test4));
print "\n";
var_dump($inst->validInput($test5));
print "\n";
var_dump($inst->validInput($test6));
print "\n";
var_dump($inst->validInput($test7));
print "\n";
print "\n";

exit();
?>

This way you can use different validation methods to increase the complexity of this validation or create new validations by putting together the existing rules in a different way, or easily add new rules by adding new short methods.

  • Thanks @MartinAJ - I still use PHP more than I would like but have adopted a lot of idioms from other programming languages when I do so that my code is more readable and re-usable, and so that it is more easily composed together. I think that PHP code in general can really benefit from being written more like idiomatic Ruby, using small, terse functions that are called in composition or in chains one after another, particularly if you have a good IDE and / or debugger to follow the values from function to function. – Oliver Godby Jul 20 '16 at 02:45
-1
if ( preg_match( $string, "/^[\d\w]{6,40}$/") ) {
    // following
} else {
    // not following
}
chris85
  • 23,846
  • 7
  • 34
  • 51
xc Liu
  • 23
  • 1
  • 1
  • 5