1

I am insanely green with regular expressions. Here is what I am trying to accomplish: I want to require an 8 character password that allows upper and lowercase letters, numbers and !@#$%^&*-_ characters. Here is what I have that doesn't appear to be working:

preg_match('([A-za-z0-9-_!@#$%^&*]{8,})', $password)

Am I missing something really obvious?

Update: Yes, I was missing something really obvious - the open bracket [. However it still returns true when I use characters like a single quote or bracket. (Which are what I am trying to avoid.)

Alan Moore
  • 73,866
  • 12
  • 100
  • 156
drewwyatt
  • 5,989
  • 15
  • 60
  • 106
  • 1
    Is that your actual regular expression? You're missing the first bracket and also your first range should be A-Z – Brian Roach Jan 10 '12 at 02:10
  • 1
    Any particular reason you're restricting the character set instead of allowing all characters? – FtDRbwLXw6 Jan 10 '12 at 02:11
  • I always amaze when see any restrictions on password character set. Why wouldn't I use `,` (comma) in my password?! – zerkms Jan 10 '12 at 02:13
  • I want to make password validation as simple as possible - I didn't want to have to escape anything before uploading to the database if possible. – drewwyatt Jan 10 '12 at 02:14
  • 1
    you shouldn't be storing the plaintext password in the database anyways, always hash and salt first – Mercurybullet Jan 10 '12 at 02:17
  • @anwyatt: that's because you need to **hash** your passwords. Plain-text passwords are bad, m'kay – zerkms Jan 10 '12 at 02:17

2 Answers2

3

Basically you miss an opening [ character group bracket here:

              ↓
 preg_match('([A-za-z0-9-_!@#$%^&*()]{8,})', $password)

And you should also use delimiters. The parens will behave as such, but it's better to use a different pair to avoid ambiguity with a capture group:

 preg_match('/^([A-za-z0-9-_!@#$%^&*()]{8,})$/', $password)

This also adds start ^ and end $ assertions to match the whole string.

Community
  • 1
  • 1
mario
  • 144,265
  • 20
  • 237
  • 291
  • 2
    Also, `A-z` should be `A-Z` and the hyphen (`-`) should be escaped: `\-`. – FtDRbwLXw6 Jan 10 '12 at 02:16
  • 1
    Missed the case mismatch. The unescaped hyphen will work *by accident*, as it follows a valid range, it cannot be part of a range itself. (Might be a peculiarity of PCRE though.) – mario Jan 10 '12 at 02:18
  • Thank you very much. It worked, but I am still a bit unsure why. What did the start and end assertions do? (please forgive my ignorance) – drewwyatt Jan 10 '12 at 02:21
  • 1
    @anwyatt: Basically your regex was only asserting the middle part of the subject string. If you do not add `^` and `$` than the `[...]{8}` group will not apply to the whole string. So a disallowed character might appear after position 9, while the regex happily just asserts the first 8 characters. – mario Jan 10 '12 at 02:24
0

This may be easier to break into individual rules. I.e. a rule to check if the password is at least 8 characters long, another to check for an uppercase, another for lowercase, etc.

Also, it looks like you have some special characters in terms of regular expressions without any escaping. For example, the * character has special meaning in regular expressions other than some special cases. It either needs to be escaped \* or in brackets [*]

Mercurybullet
  • 889
  • 1
  • 10
  • 20