This pattern would allow all characters that's not a digit or a-Z.
[^\da-zA-Z]
Regarding the \W it's a negated \w, which is the same as [A-Za-z0-9_]. Thus will \W be all characters that's not an english letter, digit or an underscore.
As I mentioned as a comment this is a great resource for learning regex. And here's a good site to test the regex.
Answer from Marcus on Stack OverflowThis pattern would allow all characters that's not a digit or a-Z.
[^\da-zA-Z]
Regarding the \W it's a negated \w, which is the same as [A-Za-z0-9_]. Thus will \W be all characters that's not an english letter, digit or an underscore.
As I mentioned as a comment this is a great resource for learning regex. And here's a good site to test the regex.
In case you want to match on special characters
preg_match('/[\'\/~`\!@#\
input)
If I correctly understand you want only this characters - backward slash,forward slash,single quote,double quotes to be disabled for you password validation. So here is the code:
public function check_password($str){
return ( preg_match('/^[^\\\"\'\/]+$/i', $str));
}
Try like this,
public function check_password($str){
return (!preg_match('/^(?=.*\d)(?=.*[A-Za-z])[0-9A-Za-z!@#
/', $str)) ? FALSE : TRUE;
}
I think this should look like that:
if(!preg_match('/^(?=.*\d)(?=.*[A-Za-z])[0-9A-Za-z!@#
/', $password)) {
echo 'the password does not meet the requirements!';
}
Between start -> ^
And end -> $
of the string there has to be at least one number -> (?=.*\d)
and at least one letter -> (?=.*[A-Za-z])
and it has to be a number, a letter or one of the following: !@#$% -> [0-9A-Za-z!@#$%]
and there have to be 8-12 characters -> {8,12}
As user557846 commented to your question, I would also suggest you to allow more characters, I usually (if i use a maximum) take at least 50 :)
btw, you might want to take a look at this regex tutorial
preg_match('/^(?=.*\d)(?=.*[@#\-_$%^&+=§!\?])(?=.*[a-z])(?=.*[A-Z])[0-9A-Za-z@#\-_$%^&+=§!\?]{8,20}$/',$password)
- at least one lowercase char
- at least one uppercase char
- at least one digit
- at least one special sign of @#-_$%^&+=§!?
You could split your regex into different checks.
It will allow you to write more readable conditions and to display specific error messages. Although, regexp patterns will be easier to write and to understand.
i.e. :
$errors = array();
if (strlen($pass) < 8 || strlen($pass) > 16) {
$errors[] = "Password should be min 8 characters and max 16 characters";
}
if (!preg_match("/\d/", $pass)) {
$errors[] = "Password should contain at least one digit";
}
if (!preg_match("/[A-Z]/", $pass)) {
$errors[] = "Password should contain at least one Capital Letter";
}
if (!preg_match("/[a-z]/", $pass)) {
$errors[] = "Password should contain at least one small Letter";
}
if (!preg_match("/\W/", $pass)) {
$errors[] = "Password should contain at least one special character";
}
if (preg_match("/\s/", $pass)) {
$errors[] = "Password should not contain any white space";
}
if ($errors) {
foreach ($errors as $error) {
echo $error . "\n";
}
die();
} else {
echo "$pass => MATCH\n";
}
Hope it helps.
You can try this:
^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?!.* )(?=.*[^a-zA-Z0-9]).{8,16}$
It covers all your requirment
Explanation
(?=.*\d)Atleast a digit(?=.*[a-z])Atleast a lower case letter(?=.*[A-Z])Atleast an upper case letter(?!.* )no space(?=.*[^a-zA-Z0-9])at least a character excepta-zA-Z0-9.{8,16}between 8 to 16 characters
Sample Code:
<?php
/m';
$str = 'Jtuhn
12J@k
jok
Joan 12@45
Jghf2@45
Joan=?j123j
';
preg_match_all(
str, $matches);
print_r($matches);
?>
Run it here
Use the following pattern:
$strong_password = preg_match('/^(?=.[a-z])(?=.[A-Z])(?=.\d)(?=.[^A-Za-z\d])[\s\S]{6,16}$/', $string);
^ --> start of string
(?=.*[a-z]) --> at least one lowercase letter
(?=.*[A-Z]) --> at least one uppercase letter
(?=.*\d) --> at least one number
(?=.*[^A-Za-z\d]) --> at least one special character
[\s\S]{6,16} --> total length between 6 and 16
$ --> end of string
PHP regex needs regex delimiters also, so use:
$pattern = '/(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$/';
You may need to escape some special characters used by the Regex Engine. And by the way, you could as well do that in one Go as shown below. Quick-Test Here.
<?php
/*public static*/ function encPasswordCheckFailed($password) {
// THIS READS:
// IF THE PASSWORD DOES CONTAIN AN UPPER-CASE CHARACTER
// AND ALSO DOES CONTAIN A LOWER-CASE CHARACTER
// AND STILL DOES CONTAIN A NUMERIC CHARACTER
// AND EVEN MORE, DOES CONTAIN ANY OF THE SPECIFIED SPECIAL CHARACTERS
// RETURN FALSE OTHERWISE RETURN TRUE
if (preg_match('/[A-Z]+/', $password) && // CHECK FOR UPPERCASE CHARACTER
preg_match('/[a-z]+/', $password) && // AND CHECK FOR LOWERCASE CHARACTER
preg_match('/[0-9]+/', $password)&& // AND CHECK FOR NUMERIC CHARACTER
preg_match('/[\!@#$%\^&\*\(\)\-\+<>]+/', $password) // AND CHECK FOR SPECIAL CHARACTER
) {
return false;
}
return true;
}
var_dump( encPasswordCheckFailed("abcd123") ); //<== boolean true
var_dump( encPasswordCheckFailed("abcD123") ); //<== boolean true
var_dump( encPasswordCheckFailed("abcD1@23-") ); //<== boolean false
The dash/minus character is your issue, as when inside a character group, it denotes a character range.
You need to either:
- Escape it with a backslash, so that it isn't treated as a special character:
/[!@#$%^&*()\-+<>]+/ - Or put it at the end of the pattern, so the PCRE engine knows it can't possibly denote a range:
/[!@#$%^&*()+<>-]+/
Similarly, the caret (^) is also a special character, denoting negation when inside a character group, but because you didn't put it at the very first position inside the character group, the PCRE engine knows it has no special meaning in your case.
[\W]+ will match any non-word character.
but to match only the characters from the question, use this:
$string="sadw$"
if(preg_match("/[\[^\'£$%^&*()}{@:\'#~?><>,;@\|\\\-=\-_+\-¬\`\]]/", $string)){
//this string contain atleast one of these [^'£$%^&*()}{@:'#~?><>,;@|\-=-_+-¬`] characters
}
Use preg_match. This function takes in a regular expression (pattern) and the subject string and returns 1 if match occurred, 0 if no match, or false if an error occurred.
$input = 'foo';
$pattern = '/[\'\/~`\!@#\$%\^&\*\(\)_\-\+=\{\}\[\]\|;:"\<\>,\.\?\\\]/';
if (preg_match($pattern, $input)){
// one or more matches occurred, i.e. a special character exists in $input
}
You may also specify flags and offset for the Perform a Regular Expression Match function. See the documentation link above.
In no particular order:
That hashing method is terrible and insecure. Hashes must be costly (slow) most of all, and they must contain a unique salt. Use
password_hash, don't invent your own.- If that is the required hashing method: move away from it ASAP. But at the very least,
utf8_encodeis entirely superfluous, since you're only allowing ASCII characters to begin with and it won't do anything in that case.
- If that is the required hashing method: move away from it ASAP. But at the very least,
Don't validate strings you have already altered (here: after
mysqli_real_escape_string).- You're already using mysqli, use prepared statements rather than tedious and error prone escaping.
- Disallowing "special characters" in passwords makes them weaker, not stronger. Unless you have strong business reasons for this restriction (which legitimately may exist), don't limit the allowed character set.
- Use more functions to make your code more readable.
- Name your SQL columns, don't rely on the implicit order.
- Use
DEFAULTvalues in your database table definitions instead of passing default values through the query, if possible. - Check whether your SQL query succeeded (and/or use mysqli's exception error mode); presumably you have a
UNIQUEconstraint on the username, so the query may legitimately fail, and your code doesn't even know it.
function validateUsername($name) {
return ctype_alnum($name) && strlen($name) >= 6;
}
function validatePassword($str) {
return ctype_alnum($str)
&& strlen($str) >= 8
&& preg_match('/[A-Z]/', $str)
&& preg_match('/[a-z]/', $str)
&& preg_match('/[0-9]/', $str);
}
function createUser(mysqli $db, $name, $password) {
$stmt = $db->prepare('INSERT INTO `accounts` (`name`, `password`) VALUES (?, ?)');
$stmt->bind_param('ss', $name, password_hash($password, PASSWORD_DEFAULT));
return $stmt->execute();
}
if (!validateUsername($_POST['name'])) {
echo 'Invalid name';
} else if (!validatePassword($_POST['password'])) {
echo 'Invalid password';
} else if ($_POST['password'] !== $_POST['repeat_password']) {
echo "Passwords don't match";
} else if (!createUser($db_link, $_POST['name'], $_POST['password'])) {
echo 'Something went wrong'; // add better error handling here
} else {
echo 'Account created';
}
Of course, you'll probably want to collect all the errors and output them next to the actual <input> elements when you inform the user about errors, instead of just failing on the first error that is produced. That's a bit too broad to tackle here though. And this could all be further improved with OOP or other larger architectural choices of course…
As an extension of deceze's excellent critique, I would like to advise that you validate the password with just one preg_match() call rather than five function calls including three separate preg_match() calls. The cost to this may mean reduced code comprehension depending on your understanding of regex, but it will yield more concise code and perform more efficiently.
function validatePassword($pass){
// permitted characters throughout string ------------------------↓↓↓↓↓↓↓↓
return preg_match('/^(?=[^A-Z]*[A-Z])(?=[^a-z]*[a-z])(?=[^\d]*\d)[a-zA-Z\d]{8,}$/',$pass)?true:false;
// required characters----------↑↑↑-------------↑↑↑-----------↑↑ ↑-minimum length (no max)
}
Here is a PHP demo.
Regex Breakdown:
^ # match from start of string
(?=[^A-Z]*[A-Z]) # lookahead for one uppercase letter (without advancing)
(?=[^a-z]*[a-z]) # lookahead for one lowercase letter (without advancing)
(?=[^\d]*\d) # lookahead for one digit (without advancing)
[a-zA-Z\d]{8,} # only match if string is comprised of 8 or more of these characters
$ # match until end of string
To relax the valid characters range, you might like to alter the character class just before $ to use .{8,} or specifically declare additional valid characters with [a-zA-Z\d!@#$%^&*()]{8,}.
Just add a starting anchor to your regex,
^(?=.*?[a-z])(?=.*?[A-Z])(?=.*?[0-9])
OR
^(?=.*?[a-z])(?=.*?[A-Z])(?=.*?[0-9]).*
Example:
$yourstring = 'Ab';
$regex = '~^(?=.*?[a-z])(?=.*?[A-Z])(?=.*?[0-9])~m';
if (preg_match($regex, $yourstring)) {
echo 'Yes! It matches!';
}
else {
echo 'No, it fails';
} // No, it fails
I always try to avoid regex if it's possible so I took a different approach to the problem. The below code will test the password for at least one uppercase, one lowercase and one digit.
function isValidPassword($password)
{
$hasUppercase = false;
$hasLowercase = false;
$hasDigit = false;
foreach (str_split($password) as $char)
{
$charAsciiValue = ord($char);
if ($charAsciiValue >= ord('A') && $charAsciiValue <= ord('Z')) {
$hasUppercase = true;
}
if ($charAsciiValue >= ord('a') && $charAsciiValue <= ord('z')) {
$hasLowercase = true;
}
if ($charAsciiValue >= ord('0') && $charAsciiValue <= ord('9')) {
$hasDigit = true;
}
}
return $hasUppercase && $hasLowercase && $hasDigit;
}
var_dump(isValidPassword('Ab9c'));
var_dump(isValidPassword('abc'));
Output
bool(true)
bool(false)
\$ already means "literal $" in PHP strings, so when put in a regex it just means "end of string".
Try \\\$ instead.
I think the correct regex to retrieve the 'button' tag should be : \{\$button([^\}]*)\}
You can try your expression on http://regexpal.com/
So with php :
preg_match("/\{\$button([^\}]*)\}/s", $content, $match );
In your pattern, you need to use single quote instead of double ;)
So it will be like this
$reg_password = '/^[-_0-9a-záàâäãåçéèêëíìîïñóòôöõúùûüýÿæœÁÀÂÄÃÅÇÉÈÊËÍÌÎÏÑÓÒÔÖÕÚÙÛÜÝŸÆŒ0\d!@#$%^&*()_\+\{\}:\"<>?\|\[\];\',\.\/\x5c~]{6,30}$/i';
You don't need to call preg_match multiple times, just use lookahead to enforce your rules as in this regex:
^(?=.*?\d)(?=.*?[a-z])[-\wáàâäãåçéèêëíìîïñóòôöõúùûüýÿæœÁÀÂÄÃÅÇÉÈÊËÍÌÎÏÑÓÒÔÖÕÚÙÛÜÝŸÆŒ0\d!@#$%^&*()+{}:"<>?|\[\];',./\x5c~]{6,30}$
RegEx Demo
Code:
$re = "`^(?=.*?\\d)(?=.*?[a-z])[-\\wáàâäãåçéèêëíìîïñóòôöõúùûüýÿæœÁÀÂÄÃÅÇÉÈÊËÍÌÎÏÑÓÒÔÖÕÚÙÛÜÝŸÆŒ0\\d!@#$%^&*()+{}:\"<>?|\\[\\];',./\\x5c~]{6,30}$`mu";
$str = "9Gq!Q23Lne;<||.\'/\\";
if (!preg_match($re, $input)) {
echo "you failed";
}