4

I not getting the desired effect from a script. I want the password to contain A-Z, a-z, 0-9, and special chars.

  • A-Z
  • a-z
  • 0-9 >= 2
  • special chars >= 2
  • string length >= 8

So I want to force the user to use at least 2 digits and at least 2 special chars. Ok my script works but forces me to use the digits or chars back to back. I don't want that. e.g. password testABC55$$ is valid - but i don't want that.

Instead I want test$ABC5#8 to be valid. So basically the digits/special char can be the same or diff -> but must be split up in the string.

PHP CODE:

$uppercase = preg_match('#[A-Z]#', $password);
$lowercase = preg_match('#[a-z]#', $password);
$number    = preg_match('#[0-9]#', $password);
$special   = preg_match('#[\W]{2,}#', $password); 
$length    = strlen($password) >= 8;

if(!$uppercase || !$lowercase || !$number || !$special || !$length) {
  $errorpw = 'Bad Password';
5
  • Ok, and what is the problem with that code? Commented Jul 3, 2012 at 20:57
  • I'm pretty sure, you can combine this into a single regex. Commented Jul 3, 2012 at 21:01
  • The code works however not to the desired effect. Note my pw example above Commented Jul 3, 2012 at 21:04
  • I'm just forcing the user to make a more secure password. How am I "stopping" you Dagon? I don't see issue. You may have a weak "preferred password" in my opinion. Commented Jul 3, 2012 at 21:08
  • The simple answer is, don't use a regex. A regex is not designed to do this, and the amount of effort you need to put into twisting its arm to your will could be used to easily create a more efficient solution. Commented Jul 3, 2012 at 21:22

4 Answers 4

11

Using "readable" format (it can be optimized to be shorter), as you are regex newbie >>

^(?=.{8})(?=.*[A-Z])(?=.*[a-z])(?=.*\d.*\d.*\d)(?=.*[^a-zA-Z\d].*[^a-zA-Z\d].*[^a-zA-Z\d])[-+%#a-zA-Z\d]+$

Add your special character set to last [...] in the above regex (I put there for now just -+%#).


Explanation:

^                              - beginning of line/string
(?=.{8})                       - positive lookahead to ensure we have at least 8 chars
(?=.*[A-Z])                    - ...to ensure we have at least one uppercase char
(?=.*[a-z])                    - ...to ensure we have at least one lowercase char
(?=.*\d.*\d.*\d                - ...to ensure we have at least three digits
(?=.*[^a-zA-Z\d].*[^a-zA-Z\d].*[^a-zA-Z\d]) 
                               - ...to ensure we have at least three special chars
                                    (characters other than letters and numbers)
[-+%#a-zA-Z\d]+                - combination of allowed characters
$                              - end of line/string
Sign up to request clarification or add additional context in comments.

9 Comments

Omega, I appreciate your response however I find your form of RegEx confusing as I am a novice. Can you elaborate that code in pieces please?
Nice answer... was that (?= a look before or a look after? By the way you should explain that.
@FabioAnselmo - I have updated my answer with such information
@rekire - (?= ... ) is a positive lookahead (see updated answer)
How does (?=.*[^a-zA-Z\d].*[^a-zA-Z\d]) ensure special chars? The RegEx reference shows \W as special chars. Thanks for the explanation though. Also for chars allowed - say I want @#$ would that look like this: [/@/#/$a-zA-Z\d]+
|
1
((?=(.*\d){3,})(?=.*[a-z])(?=.*[A-Z])(?=(.*[!@#$%^&]){3,}).{8,})

test$ABC5#8 is not valid because you ask more than 2 digits and spec symbols

A-Z
a-z
0-9 > 2
special chars > 2
string length >= 8

2 Comments

Hey sorry for the confusion. Note the code. It is invalid because the characters not adjacent. It validates if for example I use: test$$ABC44 I will corrected the example. sorry
switch {3,} to {2,} in digit and spec symbols and it will be pass
0

For matching length of string including special characters:

$result = preg_match('/^(?=.[a-z])(?=.[A-Z])(?=.\d)(?=.[^A-Za-z\d])[\s\S]{6,16}$/', $string);

Answer explained: https://stackoverflow.com/a/46359397/5466401

Comments

0

This will do the trick. Look ahead is nice for this...

/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d.*\d)(?=.*\W.*\W)[a-zA-Z0-9\S]{4,}$/

EXPLAINED in pieces below

Look ahead/require for a lower case:

(?=.*[a-z])

Look ahead/require an uppercase:

(?=.*[A-Z])

Look ahead/require 2 digits:

(?=.*\d.*\d)

Look ahead/require any 2 non-word chars (same as [^a-zA_Z0-9_]):

(?=.*\W.*\W)

Entire password must contain a minimum of 4, a maximum is not defined, and only alpha numeric and special chars (non white-space):

[\S]{4,}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.