Validate password policy with PHP preg_match - php

I'm trying to validate a password using preg_match and RegEx but it doesn't seem to work. What I want to do is: ensure the password meets the following minimal conditions:
- Contains mixed case letters
- Contains atleast one number
- The rest can be anything as long as the two conditions above are met.
I've tried the following RegEx but it doesn't seem to work properly:
(?=.*?[a-z])(?=.*?[A-Z])(?=.*?[0-9])
I've had other previous easier RegEx'es like: [A-Za-z0-9] but without success. I'm checking if preg_match($string, $pattern) == 0 (meaning the pattern doesn't match => validation fails) but it always returns 0. What am I doing wrong ?

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)

I offer a different solution, mainly because regexp provides little error reporting, and you would have to manually test the string afterwards anywhay for cohesion. Consider breaking the patterns apart and adding their own error. Iterate each of the requirements, and test the pattern. Push errors into an array and check after for their existence. Return a predeclared variable as true/false for the purpose of validating using if(validate_password($pass)):. Here's the mockup:
function validate_password($pass){
$requirements = array();
//uppercase
$requirements['uppercase']['pattern'] = '/[A-Z]/';
$requirements['uppercase']['error'] = 'Your password must contain at least one uppercase letter.';
//lowercase
$requirements['lowercase']['pattern'] = '/[a-z]/';
$requirements['lowercase']['error'] = 'Your password must contain at least one lowercase letter.';
//requires a number
$requirements['number']['pattern'] = '/[0-9]/';
$requirements['number']['error'] = 'Your password must contain at least one number.';
//special characters
$requirements['special_character']['pattern'] = '/[!##$%^&*()\\-_=+{};\:,<\.>]/';
$requirements['special_character']['error'] = 'Your password must contain at least one special character.';
//length
$requirements['length']['pattern'] = '/^.{8,}/';
$requirements['length']['error'] = 'Your password must be at least 8 characters in length total.';
$is_valid = false; //our flag to return as true once all tests have passed.
$errors = false;
//validate all requirements
foreach($requirements as $idx => $req):
if(preg_match($req['pattern'], $pass, $matches)):
$is_valid = true;
else:
$errors[] = $req['error'];
$is_valid = false;
endif;
endforeach;
//if we had errors above
if($errors):
$is_valid = false;
foreach($errors as $error):
echo '<p>', $error, '</p>';
endforeach;
endif;
return $is_valid;
}
$pass = 'j!Adz6'; //change this to test
echo validate_password($pass);
And an eval.in example for your pleasure.

Related

I am trying to change my if statement to a for loop using php

Basically I want to validate user input to ensure they are entering integer values. My if statement works well but my assignment is to change it to a for loop. Thanks!
my original if statement;
if (empty($scores[0]) ||
empty($scores[1]) ||
empty($scores[2]) ||
!is_numeric($scores[0]) ||
!is_numeric($scores[1]) ||
!is_numeric($scores[2])) {
$scores_string = 'You must enter three valid numbers for scores.';
break;
}
If you must use a for loop to validate the scores, then you just need to test each value in the $scores array in it:
$scores_string = '';
$len = count($scores);
for ($i = 0; $i < $len; $i++) {
if (empty($scores[$i]) || !is_numeric($scores[$i])) {
$scores_string = 'You must enter three valid numbers for scores.';
break;
}
}
if ($scores_string != '') {
echo $scores_string;
// do anything else you need
}
else {
// all is OK!
}
Demo on 3v4l.org
Note that the break in the if after you assign $scores_string saves iterating the entire array after a non-numeric value was found. If you wanted to count the number of non-numeric values, you'd increment a counter there instead.
It's better to define a function that returns a boolean to validate the parameters. If one variable of the parameters is invalid, return false immediately. Otherwise, return true.
Then use the function directly.
Check out the code below:
function isNumberScores($scores) {
foreach($socres as $score) {
if (empty($score) || !is_numeric($score)) {
return false
}
}
return true
}
if (!isNumberScores($socres)) {
$scores_string = 'You must enter three valid numbers for scores.';
// your code here
}

Is there a simple way to use FILTER_SANITIZE_NUMBER_INT to validate a phone number (in a form)?

I am trying to validate a phone number using PHP, and would like to know if there's a way to do it with FILTER_SANITIZE_NUMBER_INT instead of regex.
I need the password to enforce the xxx-xxx-xxxx format (allows '-') and max length of 12 characters.
This is my code so far. Would this work to validate any number into the xxx-xxx-xxxx format?
$phone = clean_input($_POST["phone"]);
if (empty($phone)) {
$phoneErr = "Valid phone number required";
$isValid = false;
} else {
if (!filter_var($phone, FILTERSANITIZE_NUMBER_INT)) ;
$phone_to_check = str_replace("-", "", $filtered_phone_number);
if (strlen($phone_to_check) < 10 || strlen($phone_to_check) > 12) {
$isValid = false;
}
}
I would use preg_match instead as you can cover all your needs in one statement. This regex assures that the value must have 10 digits, with optional - after the third and sixth digits.
$phone = clean_input($_POST["phone"]);
$isValid = preg_match('/^\d{3}-?\d{3}-?\d{4}$/', $phone);
Demo on 3v4l.org
I prefer using preg_match() functions for this style of regex.
An example based on your pattern
$phone = '000-000-0000';
if(preg_match("/^[0-9]{3}-[0-9]{3}-[0-9]{4}$/", $phone)) {
// $phone is valid
}
For validating using FILTER_SANITIZE_NUMBER_INT() try code below
function validate_phone_number($phone)
{
$filtered_phone_number = filter_var($phone, FILTER_SANITIZE_NUMBER_INT);
if (strlen($filtered_phone_number) < 12) {
return false;
} else {
return true;
}
}
Now below is the usage of the function that we have just created:
$phone = "444-444-5555";
if (validate_phone_number($phone) == true) {
echo "Phone number is valid";
} else {
echo "Invalid phone number";
}

Disabling some characters with preg_match

I'm having an issue with my register page, i noticed that people can register with alt codes like this "ªµµª" and i tried to fix it by using preg_replace but when i did that i couldn't register anymore, atleast not with the worldwide alphabet
final public function validName($username)
{
if(strlen($username) <= 25 && ctype_alnum($username))
{
return true;
}
return false;
}
Tried to fix it by replacing it with this
if(strlen($username) <= 25 && preg_match("/[^a-zA-Z0-9]+/", $username))
But i'm obviously doing something wrong...
Apparently, you are confusing two different uses of the caret (^) metacharacter.
Indeed, it may be two things in a regular expression:
It may assert the start of the subject, which is what you probably want.
It may negate the class, which is what you're doing in your code.
Source: http://php.net/manual/en/regexp.reference.meta.php
Here is a modified version of your code, with the caret (^) and dollar ($) signs to assert the start and the end of the strings you're analyzing:
function validName($username)
{
if (strlen($username) <= 25 && preg_match("/^[a-zA-Z0-9]+$/", $username))
{
return true;
}
return false;
}
$names = array(
'Abc1',
'Abc$',
"ªµµª"
);
foreach ($names as $name) {
echo "<br>" . $name . ': ' . (validName($name) ? 'valid' : 'invalid');
}
// -- Returns:
// Abc1: valid
// Abc$: invalid
// ªµµª: invalid
Note that you may reduce the code inside your function to one line:
function validName($username)
{
return strlen($username) <= 25 && preg_match("/^[a-zA-Z0-9]+$/", $username);
}

php: validate if field starts with certain character

I'm using the Contact Form 7 plugin on wordpress to collect data inputted in the fields, I'm now looking to set up some validation rules using this neat extension: http://code-tricks.com/contact-form-7-custom-validation-in-wordpress/
What I'm after is to only allow one word only in the text field (i.e. no whitespace) and this one word has to begin with the letter 'r' (not case sensitive).
I've written the no white space rule as follows:
//whitespace
if($name == 'WhiteSpace') {
$WhiteSpace = $_POST['WhiteSpace'];
if($WhiteSpace != '') {
if (!preg_match('/\s/',$WhiteSpace)){
$result['valid'] = true;
} else {
$result['valid'] = false;
$result['reason'][$name] = 'Invalid Entry.';
}
}
}
Is it possible to incorporate the second rule into this also? So no whitespace, and the word must begin with the letter 'r'? Any suggestions would be greatly appreciated!
EDIT:
seems core1024 answer does work, but only one of them:
//FirstField
if($name == 'FirstField') {
$FirstField = $_POST['FirstField'];
if($FirstField != '') {
if (!preg_match("/(^[^a]|\s)/i",$FirstField)){
$result['valid'] = true;
} else {
$result['valid'] = false;
$result['reason'][$name] = 'Invalid Entry.';
}
}
}
//__________________________________________________________________________________________________
//SecondField
if($name == 'SecondField') {
$SecondField = $_POST['SecondField'];
if($SecondField != '') {
if (!preg_match("/(^[^r]|\s)/i", $SecondField)) {
$result['valid'] = true;
} else {
$result['valid'] = false;
$result['reason'][$name] = 'Invalid Entry.';
}
}
}
I want to use this code twice, once to validate the first character being a on one field the second instance with the first character being r on another field. But it only seems the SecondField validation rule is working.
Try to use:
preg_match('/^r[^\s]*$/i',$WhiteSpace)
instead of:
!preg_match('/\s/',$WhiteSpace)
You need this:
if (!preg_match("/(^[^r]|\s)/i", $WhiteSpace)) {
It matches any string that doesn't start with r/R or contain space.
Here's a test:
$test = array(
'sad',
'rad',
'ra d'
);
foreach($test as $str) {
echo '"'.$str.'" -> '.preg_match('/(^[^r]|\s)/i', $str).'<br>';
}
And the result:
"sad" -> 1
"rad" -> 0
"ra d" -> 1

Function to validate username and password not working [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Regular Expression matching for entire string
On my form page, I am trying to make it only accept alphanumeric characters for my username and password and require that they be from 6 to 15 characters. When I type in invalid data, it will insert it into the database rather than throw the user error that I defined in my CheckAlNum function.
functions.php
function checkAlNum($whichField)
{
if (preg_match('/[A-Za-z0-9]+/', $_POST[$whichField])){
if ( (!count(strlen($whichField) >= 6)) OR (!count(strlen($whichField) <= 15 ))) {
$message1 = '<p> Username and password must be between 6 and 15 characters </p>';
return user_error($message1);
}
else{
return true;
}
}
else {
$message = '<p>Username and password can only be numbers or letters</p>';
return user_error($message);
}
}
Form.php
if (count($_POST) > 0) {
//Validate the inputs
$errorMessages = array();
//Validate the username
$item5 = checkAlNum('username');
if($item5 !== true) {
$errorMessages[] = $item5;
}
//Validate the password
$item6 = checkAlNum('password');
if($item6 !== true) {
$errorMessages[] = $item6;
}
//Validate the firstName and lastName
$item1 = checkNameChars('firstName');
if ($item1 !== true) {
$errorMessages[] = $item1;
}
$item2 = checkNameChars('lastName');
if ($item2 !== true) {
$errorMessages[] = $item2;
}
//Validate the office name
$item3 = checkOfficeChars('office');
if ($item3 !== true) {
$errorMessages[] = $item3;
}
//Validate the phone number
$item4 = validate_phone_number('phoneNumber');
if($item4 !== true) {
$errorMessages[] = $item4;
}
//Check to see if anything failed
if (count($errorMessages) == 0) {
$newEmployee = new Person;
$newEmployee -> insert();
}
else { //Else, reprint the form along with some error messages
echo "<h2><span>Error</span>: </h2>";
foreach($errorMessages as $msg) {
echo "<p>" . $msg . "</p>";
}
}
}
?>
I've tried playing around with the nesting of the if-else statements of the checkAlNum function and also the regex (although I'm pretty sure the regex is right). Maybe I'm just missing something really silly?
function checkAlNum($whichField)
{
if (preg_match('/^[a-z0-9]{6,15}$/i', $_POST[$whichField])) {
return true;
}
else {
$message = '<p>Username and password can only be numbers or letters, 6-15 characters long</p>';
return user_error($message);
}
}
Without the ^ and $ anchors, your regex only checks whether there are alphanumerics anywhere in the field, not that the whole thing is alphanumeric. And changing + to {6,15} implements the length check here, so you can remove that extra check in your code.
I think the second if statement is incorrect. It should be like this:
if ( !( (!count(strlen($whichField) >= 6)) OR (!count(strlen($whichField) <= 15 )) ) ) {
// ... do something
}
This is due to De Morgan Rule which states
A AND B = !( !A OR !B )
In any case, I would not do my checks this way, strucurally you will end up with too many nested if statements that are hard to maintain and make your code look unpretty. Try avoiding nested conditions in your code.
Barmar's answer is the best. But if you want to keep your if statement to check string length, you need to remove the count() as you are already checking the length using strlen().
if ( (!(strlen($whichField) >= 6)) OR (!(strlen($whichField) <= 15 ))) {

Categories