Reputation: 1799
I'm trying to match at least 1 uppercase anywhere, 1 special anywhere, 4 non-sequential numbers anywhere and length is 6 to 14.
I tried the following regex:
((?=(.*[^A-Za-z0-9])+)(?=(.*[A-Z])+)(?=(.*\d){4,})(?=.*[a-z])+)(?!=.*([\d])\\1\\1\\1\\1).{6,14}
But all the following strings are matching:
abDc#E0%F9$845,
abDc#E0%F9$8y6,
abDc#E0981,
#ab1DcE09w1234 **(4 sequential numbers)**,
#ab1111DcE09,
E$ab1Dc098,
1$Eab1Dc0989,
T3$s7p4s$123,
T1234$stPass **(4 sequential numbers)**
And doesn't match:
testpass,
abDc#E0%F9$8y67 (15 characters),
t3stpass,
te$stpass,
TestPass,
T3$stpass
How can I fix it?
Upvotes: 2
Views: 1225
Reputation: 91385
How about:
if (preg_match('/^(?=.*[A-Z])(?=(?:.*\d){4,})(?=.*[!@$%^&*()_+=-]).{6,14}$/', $string)) {
// remove all non digit
$tmp = preg_replace('/\D+/', '', $string);
if (preg_match('/0123|1234|2345|3456|4567|5678|6789|3210|4321|5432|6543|7654|8765|9876|0000|1111|2222|3333|4444|5555|6666|7777|8888|9999/', $string)) {
echo "Failed\n";
}
echo "Pass\n";
} else {
echo "Failed\n";
}
Where:
(?=.*[A-Z]) : at least one uppercase
(?=(?:.*\d){4,}) : at least 4 digits
(?=.*[!@$%^&*()_+=-]) : at least one special character
.{6,14} : from 6 to 14 character long
Upvotes: 1
Reputation: 1799
Used the following PHP page to test the regex.
1) strlen checks string length
2) first preg_match checks one or more uppercase letter
3) second preg_match checks at least 4 numbers
4) third preg_match checks 4 sequential numbers (ascending and descending)
5) fourth preg_match checks at least one special character
<?php
if (isset($_GET['string'])) {
if ($_GET['string'] != '') {
$string = $_GET['string'];
} else {
echo "Empty string.";
}
}
?>
<pre>
<html>
<head>
<title>Regular Expression Tester</title>
</head>
<body>
<form action="" method="get">
<input type="text" name="string" />
<input type="submit" value="Send" />
</form>
</pre>
<?php
if (isset($_GET['string'])) {
if(strlen($string) >= 6 && strlen($string) <= 14) { // length between 6 and 14
echo "Size between 6 and 14: <b><span style=\"color:green;\">OK</span></b>", "<br>";
if (preg_match('#[A-Z]+#', $string)) { // one or more uppercase chars
echo utf8_decode("At least one uppercase: <b><span style=\"color:green;\">OK</span></b>"), "<br>";
if (preg_match('#(?=.*[0-9]{1}.*[0-9]{1}.*[0-9]{1}.*[0-9]{1})#', $string)) { // it has at least 4 numbers anywhere
if (!preg_match('#(0123|1234|2345|3456|4567|5678|6789|3210|4321|5432|6543|7654|8765|9876|0000|1111|2222|3333|4444|5555|6666|7777|8888|9999)#', $string)) { // sequential numbers
echo utf8_decode("4 non-sequential numbers: <b><span style=\"color:green;\">OK</span></b>"), "<br>";
if (preg_match('#[!@$%^&*()_+=-]+#', $string)) { // special chars
echo utf8_decode("At least one special character: <b><span style=\"color:green;\">OK</span></b>"), "<br>";
echo utf8_decode("<br>$string <b><span style=\"color:green;\">PASSED</span></b>");
exit;
} else {
echo utf8_decode("At least one special character: <b><span style=\"color:red;\">FAILED</span></b>"), "<br>";
}
} else {
echo utf8_decode("4 non-sequential numbers: <b><span style=\"color:red;\">FAILED</span></b>"), "<br>";
}
} else {
echo utf8_decode("4 non-sequential numbers: <b><span style=\"color:red;\">FAILED</span></b>"), "<br>";
}
} else {
echo utf8_decode("At least one uppercase: <b><span style=\"color:red;\">FAILED</span></b>"), "<br>";
}
} else {
echo "Size between 6 and 14: <b><span style=\"color:red;\">FAILED</span></b>", "<br>";
}
echo utf8_decode("<br>$string <b><span style=\"color:red;\">DIDN'T PASS</span></b>");
}
?>
<pre>
</body>
</html>
</pre>
Screenshots:
EDIT: But T1e2$3t4
didn't pass, so the problem is in the 2nd preg_match. It's searching 4 numbers IN A ROW, not 4 numbers in ANY position.
EDIT 2: Changed that regex to #(?=.*[0-9]{1}.*[0-9]{1}.*[0-9]{1}.*[0-9]{1})#
and it's working completely now.
Thanks, everyone! :-)
Upvotes: 0
Reputation: 238
Try this, please test it before using it:
function validate_password($password){
if(empty($password))
return false;
if(strlen($password) < 4 || strlen($password) > 14)
return false;
$uppercase_test = preg_match('#[A-Z]+#', $password);
//include special charactors that you want
$special_test = preg_match('#[!@$%^&*()_+=-]+#', $password);
$nonsequencial_number_test = !preg_match('#(\d)\\1{4,}#', $password);
if($uppercase_test && $special_test && $nonsequencial_number_test){
return true;
}
return false;
}
var_dump(validate_password('abDc#E0%F9$8y6'));
Upvotes: 1