4

I am trying to make a check in PHP if a user changes their password their new password must be 8 or more characters and with at least 1 non-alphanumeric password. How should I check this and what would the regex be?

Checking the length is the easy part strlen >= 8. My problem is regular expressions. I really have no clue about regular expressions even after years of studying computer science.

Thanks

Johnathan Au
  • 5,244
  • 18
  • 70
  • 128
  • 2
    Why does this have to be a regular expression? – robert May 23 '12 at 14:28
  • @robert Agreed with robert, you should instead do it in many steps or else the day you want to add more conditions, you will again try to figure out how to add more conditions to your regex for something that takes no time at all to code and add to your code ;) – Mathieu Dumoulin May 23 '12 at 14:40
  • [Here's a link](http://stackoverflow.com/a/661872/862594) to an SO answer explaining whether or not you need to use multibyte functions. It's entirely dependent upon your character encoding. – nickb May 23 '12 at 15:14

6 Answers6

5

Try something like this to check if they used non-alphanumeric characters:

if( !preg_match( '/[^A-Za-z0-9]+/', $password) || strlen( $password) < 8)
{
    echo "Invalid password!";
}

The if statement will evaluate to true if the $password does not contain at least one of the characters not in the list (alphanumeric characters).

nickb
  • 59,313
  • 13
  • 108
  • 143
  • I'm *guessing* it is because it doesn't check for a special character which is required. But it wasn't me so I don't know for sure. – John Conde May 23 '12 at 14:31
  • @JohnConde - I don't think that's it because **it does** check for a special character, see [this example](http://codepad.viper-7.com/8iYGkq). – nickb May 23 '12 at 14:36
  • 1
    @nickb I did, and John Conde got it right, you are not respecting the requirement of the questions and using dangerous functions for today's context... always use mb_strlen instead, cause if i pass in "gâteaux" as a password, your detection works but i only have 7 characters, strlen will return 8 characters... – Mathieu Dumoulin May 23 '12 at 14:37
  • @nickb in any case, we didn't see the [^] it's true, but then you are not checking for alphanumberics only... – Mathieu Dumoulin May 23 '12 at 14:38
  • Again, that's yet another test case that my answer satisfies. Try an alphanumeric only password like in the example I linked above. **It doesn't validate.** And the OP didn't mention Unicode characters, if there's a need to handle them, he can modify the one function call as necessary for his locale. Wow, that's amazingly ridiculous criticism for a perfectly functional answer, especially since there's no guarantee his PHP installation **even has** the MB extension, since it's not enabled by default. – nickb May 23 '12 at 14:45
  • Yes I do have MB installed ;) When you say Unicode characters, what do you mean? – Johnathan Au May 23 '12 at 14:50
  • Fantastic! Prepend `mb_` to the call to `strlen` and you have a 100% functional answer. Next time I'll be sure to assume things that aren't in the OP in order to come up with the "correct" answers. – nickb May 23 '12 at 14:52
  • 1
    It works right now. Can I ask where it checks for a special character? – Johnathan Au May 23 '12 at 14:58
  • @JohnathanAu - For this discussion, "handling Unicode characters" just means that the password could have characters outside of the English alphabet. More specifically, it's characters that are not internally represented as a single byte, hence the need for the MB extension to handle multiple-byte characters. – nickb May 23 '12 at 15:03
  • 1
    It checks for the special character in the regular expression. The regex says "Match at least one character that is not present in the list `A-Za-z0-9`". So if it finds a non-alphanumeric character, it would return true. If there is no such character, it returns false. By inverting that logic with `!` before the function call, it causes the `if` statement to be evaluated when a non-alphanumeric character is not present. – nickb May 23 '12 at 15:03
0

This should work (untested)

if (preg_match('/^(?=.*[\W])(?=[a-z0-9])[\w\W]{8,}$/i', '123abc!$'))
{
    //error
}

It makes sure the password is 8 characters long and has at least one special character

John Conde
  • 217,595
  • 99
  • 455
  • 496
0

If you're checking the string length with strlen/mb_strlen, you can simply write a regular expression to match any non-alphanumeric character. If it matches one (or more), you're good. For example:

$password = 'asdf123!';

if(mb_strlen($password) >= 8 and preg_match('/[^0-9A-Za-z]/', $password))
{
    // password is valid
}
Jonathan S.
  • 2,238
  • 16
  • 16
  • Any reason for the downvote on this? Unless we're counting accented characters, etc. as alphanumeric, I'm not sure what's wrong with this solution. – Jonathan S. May 23 '12 at 15:47
0

To my knowledge, you can't achieve this because it's a composite condition scenario.

What you'd need to do is do it in a three step fashion:

$has8characters = (mb_strlen($_REQUEST['password']) >= 8);
$hasAlphaNum = preg_match('b[a-z0-9]+bi', $_REQUEST['password']);
$hasNonAlphaNum = preg_match('b[\!\@#$%\?&\*\(\)_\-\+=]+bi', $_REQUEST['password']);

This wasn't tested, but you are pretty close of what you want to achieve with this...

Good luck

Mathieu Dumoulin
  • 12,126
  • 7
  • 43
  • 71
  • 2
    You can do this in one regex. My answer actually handles it and can even be expanded to require more complex passwords. – John Conde May 23 '12 at 14:33
  • 1
    Doesn't this only count a handful of characters as non-alphanumeric? What about backticks, braces, pipes, etc.? – Jonathan S. May 23 '12 at 15:42
0

Try this.

~^(.*[\W]+.*){8,}$~
  • .* looks for any character 0 or more times
  • [\W]+ matches at least one non-word character
  • {8,} matches the bracketed value only if the length is 8 or more characters
  • ^ $ match the start and end of the string
Andrew Willis
  • 2,289
  • 3
  • 26
  • 53
0

This solves it. Have a try!

if(!preg_match('/^(?=.*\d)(?=.*[A-Za-z])[0-9A-Za-z!@#$%]{8,}$/', $pass)) {
  echo "Password does not meet the requirements! It must be alphanumeric and atleast 8 characters long";
}