views:

55

answers:

2

I need to use PHP to validate usernames, and I only want them to use alphanumeric, as well as dash (-), underscore (_) and period (.)

Is this right?

preg_match("/[A-Za-z0-9_-.]/",$text);
+4  A: 

No it isn't (although, I suppose you already suspected that, since otherwise you wouldn't be asking). :)

When defining a character group, the dash is used to define a range, just as you do A-Z means all characters between A and Z. However, you also do _-., meaning all characters between _ and . (I don't know which that is, but you can look it up in an ASCII-table). To allow matching of a dash in a character group, it has be placed anywhere where it can't be interpreted as a character range, which is usually first or last (but see the comments for other creative ways ;) ).

preg_match("/^[A-Za-z0-9_.-]+$/",$text);

As pointed out in the comments, you'll need to anchor it too, to make sure there are no charachters outside the matched range (that's what the ^, which matches beginning of string, and $, which matches end of string, are for). You'll also need to make sure that you can match more than one character. So add a + in there (or * if you want to allow empty strings), meaning one or more characters.

HTH

roe
@roe - would it also work if you escaped it - `\-`?
Dominic Rodger
The dash could also be escaped: `/[A-Za-z0-9_\-.]/`, or placed at the start: `/[-A-Za-z0-9_.]/` or even in between ranges: `/[A-Z-a-z0-9_.]/` to match the literal `-`.
Bart Kiers
@Bart: good point..
roe
that regex can be written simply as /[\w.-]/
newacct
@roe, But not entirely correct: I said *'in between ranges'*, but right after a range is sufficient: `[A-Za-z0-9-_.]` would do the trick.
Bart Kiers
It also needs to be anchored, right now that'd match $text as long as it had one valid character and there rest were invalid.
reko_t
@newacct: true, since we're talking perl compatible regular expressiosn.
roe
@reko_t: oh god, good point. It's not anchored, and it's missing the asterix too!
roe
@newacct: not quite - \w will also match accented and other special characters (Äáß etc.).
Tim Pietzcker
A: 

You need to anchor the pattern at beginning an end, right now it'd match $text as long as there was just one valid character and the rest were invalid. Use this:

if (preg_match('/^[\w.-]+$/', $text)) { /* valid */ }

\w is the same thing as [0-9A-Za-z_]. Another way to do it would be to inverse the pattern and search for any invalid characters and check none are matched:

if (!preg_match('/[^\w.-]/', $text)) { /* valid */ }
reko_t