This question already has answers here:
Regular expression to enforce complex passwords, matching 3 out of 4 rules
(4 answers)
Closed 9 years ago.
Sorry to all if this code is poor as I am just following through a book to and modifying it for my school project as I just started php less than a month ago.
I am trying to understand what this validation mean but can't seem to comprehend it full as I am new with php.
Code:
if (preg_match ('/^(\w*(?=\w*\d)(?=\w*[a-z])(?=\w*[A-Z])\w*){6,20}$/', $_POST['pass']) ) {
//$p = mysqli_real_escape_string ($dbc, $_POST['pass']);
$p = $_POST['pass'];
$sticky_password = $p;
} else {
$error['pass'] = 'Please enter a valid password!';
}
Any help would be really appreciated! Thanks!
Thank you very much.. :)
We have the following regex:
/^(\w*(?=\w*\d)(?=\w*[a-z])(?=\w*[A-Z])\w*){6,20}$/
The first and last / are the delimiters.
^ -> The start, $ -> The end
Which means if input is abc and your regex is /^bc$/, it won't get matched since bc is not at the beginning.
Now we have (\w*(?=\w*\d)(?=\w*[a-z])(?=\w*[A-Z])\w*){6,20}
The {6,20} is the quantifier part, which means 6 up to 20 times.
Let's break the regex further: \w*(?=\w*\d)(?=\w*[a-z])(?=\w*[A-Z])\w*
Let's provide some equivalents:
\w => [a-zA-Z0-9_]
\d => [0-9]
* => zero or more times
(?=) Is a lookahead assertion. Example /a(?=b)/ this will match any "a" followed by "b"
The purpose of those lookaheads:
(?=\w*\d) => check if there is a digit
(?=\w*[a-z]) => check if there is a lowercase letter
(?=\w*[A-Z]) => check if there is a uppercase letter
Let's take (?=\w*\d): The \w* is just there as a "workaround" in case there is [a-zA-Z0-9_]* before a digit
In the end, this regex just makes sure that the input:
is 6 to 20 characters long
that there is minimal: 1 lowercase, 1 uppercase and 1 digit
that the allowed characters are letters (upper and lowercase (a-z,A-Z)), digits and underscore.
Three interesting sites www.regexper.com, www.regular-expressions.info and www.regex101.com.
Note: Don't restrict passwords, you have to hash them anyway. Take a look here or check the other questions on SO.
Actually this pattern matches all passwords with at least 3 characters (a digit, an upper case and a lower case in any order) without a length limit (except for the regex engine). All characters must be word characters (ie: from the class \w).
The author intention was probably to match all passwords between 6 and 20 word characters with at least one digit, one upper case and one lower case, as the quantifier and the lookaheads suggest.
In short this pattern is wrong, but probably aims what this classical password validation pattern does:
^(?=\w*[A-Z])(?=\w*[a-z])(?=\w*\d)\w{6,20}$
or this one without all redundant \w:
^(?=.*[A-Z])(?=.*[a-z])(?=.*\d)\w{6,20}$
Explanation: lookaheads are zero-width assertions, they don't consume characters, they are only tests. Consequence each of them are performed from the start of the string since they are anchored to the ^. If each lookahead succeeds, then \w{6,20} is tested always from the start of the string to know if it contains only between 6 and 20 word characters. $ means the end of the string.
As said in comments, this pattern comes from the book "Effortless E-commerce" first edition, by Larry Ullman.
Even if the author wrotes:
"And, admittedly, even I often have to look up the proper syntax for patterns, but this one requires a high level of regular expression expertise."
and even if I disagree with the second part of the sentence, I think this pattern is a simple typo. However I don't know if this one has been corrected in the second edition.
Related
I need to write a regular expression that will evaluate the following conditions:
2 consecutive lower case characters
at least 1 digit
at least 1 upper case character
2 consecutive identical punctuation characters
For example, the string 'aa1A!!' should match, as should '!!A1aa'.
I have written the following regular expression:
'/(?=([a-z]){2,})(?=[0-9])(?=[A-Z])(?=(\W)\1)/'
I have found each individual expression works, but I am struggling to put it all together. What am I missing?
First, your pattern must be anchored to be sure that lookaheads are only tested from the position at the start of string. Then, since your characters can be everywhere in the string, you need to start the subpatterns inside lookahead with .*.
\W is a character class for non-word characters (all that is not [A-Za-z0-9_] that includes spaces, control characters, accented letters...). IMO, \pP or [[:punct:]] are more appropriate.
/^(?=.*[a-z]{2})(?=.*[0-9])(?=.*[A-Z])(?=.*(\pP)\1)/
About the idea to make 4 patterns instead of 1, it looks like a good idea, it tastes like a good idea, but it's useless and slower. However, it can be interesting if you want to know what particular rule fails.
So I thought I had this right?
if(!preg_match('^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+.{7,}$', $passOne)) {
$msg = "Password does not contain at least 1 number/letter, 8 character minimum requirement.";
}
I test it over at https://regex101.com/ and put ^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+.{7,}$ to work and things like RubyGlue12 pass and is a match and other things that aren't.
But no matter what, I cannot make any match in the actual PHP code. Even if the POST is a variable manually.
edit: $_POST['password'] is $passOne
Help?
You have .+.{7,} that does not make much sense since it means match any characters 1 or more times, and then any characters 7 or more times.
1 letter, 1 digit and min 8 characters regex will look like
(?i)^(?=.*[a-z])(?=.*\d).{8,}$
Regex explanation:
(?i) - Turning case sensitivity off (unless you need to check for 1 uppercase and 1 lowercase letters - then, remove the i flag and replace (?=.*[a-z]) with (?=.*[a-z])(?=.*[A-Z]))
^ - Start of string
(?=.*[a-z]) - Positive look-ahead requirement to have at least 1 letter
(?=.*\d) - Positive look-ahead requirement to have at least 1 digit
.{8,} - At least 8 characters
$ - End of string.
And PHP code is:
$re = "/^(?=.*[a-z])(?=.*\\d).{8,}$/i";
$passOne = "RubyGlue12";
//$passOne = "eee"; // uncomment to echo the error message
if(!preg_match($re, $passOne)) {
echo "Password does not contain at least 1 number/letter, 8 character minimum requirement.";
}
And yes, with preg_match function, you must use some regex delimiters. I am using / here.
Here's a regex that tests for what the password should not be, instead of what it should be.
/^(.{0,7}|[^a-z]*|[^\d]*)$/i
Example:
if (preg_match('/^(.{0,7}|[^a-z]*|[^\d]*)$/i', $passOne)) {
echo "Validation failed.\n";
}
Explanation:
There are essentially 3 separate tests within the regex (each separated by a |, and each are case-insensitive due to the i option at the end). If it passes any of the tests, then the entire validation fails.
Test 1: Does the entire string only contain 0-7 characters? Fail.
Test 2: Does the entire string contain no alpha characters? Fail.
Test 3: Does the entire string contain no digits? Fail.
Can someone explain me the meaning of this pattern.
preg_match(/'^(d{1,2}([a-z]+))(?:s*)S (?=200[0-9])/','21st March 2006','$matches);
So correct me if I'm wrong:
^ = beginning of the line
d{1,2} = digit with minimum 1 and maximum 2 digits
([a-z]+) = one or more letters from a-z
(?:s*)S = no idea...
(?= = no idea...
200[0-9] = a number, starting with 200 and ending with a number (0-9)
Can someone complete this list?
Here's a nice diagram courtesy of strfriend:
But I think you probably meant ^(\d{1,2}([a-z]+))(?:\s*)\S (?=200[0-9]) with the backslashes, which gives this diagram:
That is, this regexp matches the beginning of the string, followed by one or two digits, one or more lowercase letters, zero or more whitespace characters, one non-whitespace character and a space. Also, all this has to be followed by a number between 2000 and 2009, although that number is not actually matched by the regexp — it's only a look-ahead assertion. Also, the leading digits and letters are captures into $matches[1], and just the letters into $matches[2].
For more information on PHP's PCRE regexp syntax, see http://php.net/manual/en/pcre.pattern.php
regular-exressions.info is very helpful resource.
/'^(d{1,2}([a-z]+))(?:s*)S (?=200[0-9])/
(?:regex) are non-capturing parentheses; They aren't very useful in your example, but could be used to expres things like (?:bar)+, to mean 1 or more bars
(?=regex) does a positive lookahead, but matches the position not the contents. So (?=200[0-9]) in your example makes the regex match only dates in the previous decade, without matching the year itself.
I am trying to construct a regular expression for a string which can have 0 upto 4 characters. The characters can only be 0 to 9 or a to z or A to Z.
I have the following expression, it works but I dont know how to set it so that only maximum of 4 characters are accepted. In this expression, 0 to infinity characters that match the pattern are accepted.
'([0-9a-zA-Z\s]*)'
You can use {0,4} instead of the * which will allow zero to four instances of the preceding token:
'([0-9a-zA-Z\s]{0,4})'
(* is actually the same as {0,}, i.e. at least zero and unbounded.)
If you want to match a string that consists entirely of zero to four of those characters, you need to anchor the regex at both ends:
'(^[0-9a-zA-Z]{0,4}$)'
I took the liberty of removing the \s because it doesn't fit your problem description. Also, I don't know if you're aware of this, but those parentheses do not form a group, capturing or otherwise. They're not even part of the regex; PHP is using them as regex delimiters. Your regex is equivalent to:
'/^[0-9a-zA-Z]{0,4}$/'
If you really want to capture the whole match in group #1, you should add parentheses inside the delimiters:
'/(^[0-9a-zA-Z]{0,4}$)/'
... but I don't see why you would want to; the whole match is always captured in group #0 automatically.
You can use { } to specify finite quantifiers:
[0-9a-zA-Z\s]{0,4}
http://www.regular-expressions.info/reference.html
You can avoid regular expressions completely.
if (strlen($str) <= 4 && ctype_alnum($str)) {
// contains 0-4 characters, that are either letters or digits
}
ctype_alnum()
I need a regular expression for string validation. String can be empty, can have 5 digits, and can have 9 digits. Other situations is invalid. I am using the next regex:
/\d{5}|\d{9}/
But it doesn't work.
Just as Marc B said in the comments, I would use this regular expression:
/^(\d{5}(\d{4})?)?$/
This matches either exactly five digits that might be followed by another four digits (thus nine digits in total) or no characters at all (note the ? quantifier around the digits expression that makes the group optional).
The advantage of this pattern in opposite to the other mentioned patterns with alternations is that this won’t require backtracking if matching five digits failed.
use anchors and "?" to allow empty string
/^(\d{5}|\d{9})?$/
~^(?:\d{5}|\d{9}|)$~
You forgot the anchors ^ and $. Without them the string would match those digits anywhere in the string, not only at beginning or end. Furthermore you didn't cover the empty string case.
"doesn't work" isn't much help. but wouldn't it be something like this?
/^(\d{5}|\d{9}|)$/
(Bit rusty on regexp, but i'm trying to do is "start, then 5 digits OR 9 digits OR nothing, then end)
The answer as to why it doesent work is with Perl style regex's alternations are prioritized from left to right.
Change it to:
/\d{9}|\d{5}/ (Though, this won't tell you anything else about 6-8 and 10-infinity
unless its anchored with assertions or something else.)
/^(\d{5}|\d{9}|)$/