Home > Enterprise >  How to combine many Regex in PHP
How to combine many Regex in PHP

Time:06-10

I want to check if The string has 16 characters, contains digits, contains letters, and does not have any special characters. I already did it on javascript but users still cheating and some are adding < script > tags in the user input, so I need to convert it to PHP for server-side verification. But I am very confused, I am new to PHP regex, What is wrong with my code? How to combine all of these regexes into one line as I am very confused about too many AND Logical operators, Thanks:

<?php
function create($referrer=null){
  if(strlen($referrer) == 16 and (!empty(preg_match('/\d /g', $referrer))) and (!empty(preg_match('/[a-zA-Z]/g', $referrer)) and empty(preg_match('/[!@#$%^&*()_ \-=\[\]{};\':"\\|,.<>\/?] /', $referrer)))){
      echo 'The string has 16 characters, contains digits, contains letters, and does not have any special characters.';
  }
}

create("kdsygdbg7j6f5ps2");
                                            
?>  

CodePudding user response:

You could use one regex for this

But for the sake of the explanation I have explained it with the example below.

One regex:

var_dump(preg_match('/^[a-zA-Z0-9]{16}$/', 'oaiwejfio12321wejfewiojiowea')); //0, too long
var_dump(preg_match('/^[a-zA-Z0-9]{16}$/', '**(#&($#@')); //0, invalid chars
var_dump(preg_match('/^[a-zA-Z0-9]{16}$/', '1234567891234567')); //1, correct

Preg_match

The following information is useful to know about preg_match:

preg_match() returns 1 if the pattern matches given subject, 0 if it does not, or false on failure.

Your usage of !empty

You use !empty in your code, this makes it a bit unreadable. preg_match returns 1 or 0, so it is better to compare it to those values. But !empty can actually work, please look at the following results:

var_dump(!empty(1)); //true
var_dump(!empty(0)); //false

Regex with preg_match explanation

1. !empty(preg_match('/\d /g', $referrer))

I have replaced this with the following: preg_match('/[0-9]/', $referrer) === 1 , since g is an unknown modifier. Have a look at the class ShouldContainDigits in the code example at the bottom.

2. empty(preg_match('/[a-zA-Z]/g', $referrer))

I have replaced this with the following: preg_match('/[a-zA-Z]/', $value) === 1 , since g is an unknown modifier. Have a look at the class ShouldContainLetters in the code example at the bottom.

3. empty(preg_match('/[!@#$%^&*()_ \-=\[\]{};\':"\\|,.<>\/?] /', $referrer))

I have replaced this with the following: (preg_match('/[!@#$%^&*()_ \-=\[\]{};\':"\\|,.<>\/?] /', $referrer) === 0). Have a look at the class ShouldNotContainSpecialChars in the code example at the bottom.

Complete code example

I have refactored the example to make it more clear what each regex should be doing. Add the following code to test.php and run php test.php:

<?php

final class Result 
{
    private $errors = [];
    public function __construct() {}

    public function withError(string $error) : Result 
    {
        $result = clone $this;
        $result->errors[] = $error;
        return $result;
    }

    public function getErrors() : array 
    {
        return $this->errors;
    }

    public function isValid() : bool 
    {
        return empty($this->errors);
    }
}

interface ValidatorStrategy 
{
    public function isValid(string $value) : bool;
    public function getError() : string;
}

final class ShouldBe16CharsInLength implements ValidatorStrategy 
{
    public function isValid(string $value) : bool
    {
        return strlen($value) === 16;
    }

    public function getError() : string
    {
        return "The string does not have 16 chars";
    }
}

final class ShouldContainDigits implements ValidatorStrategy 
{
    public function isValid(string $value) : bool
    {
        return preg_match('/[0-9]/', $value) === 1;
    }

    public function getError() : string
    {
        return "The string does not contain digits";
    }
}

final class ShouldContainLetters implements ValidatorStrategy 
{
    public function isValid(string $value) : bool
    {
        return preg_match('/[a-zA-Z]/', $value) === 1;
    }

    public function getError() : string
    {
        return "The string does not contain letters";
    }
}

final class ShouldNotContainSpecialChars implements ValidatorStrategy
{
    public function isValid(string $value) : bool
    {
        return (preg_match('/[!@#$%^&*()_ \-=\[\]{};\':"\\|,.<>\/?] /', $value) === 0);
    }

    public function getError() : string
    {
        return "The string does contain special chars";
    }
}

final class Validator 
{
    private $strategies;
    public function __construct(array $strategies)
    {
        $this->strategies = $strategies;
    }

    public function validate(string $value) : Result 
    {
        $result = new Result();
        foreach($this->strategies as $strategy) {
            if(!$strategy->isValid($value)) {
                $result = $result->withError($strategy->getError());
            }
        }
        return $result;
    }
}

$validator = new Validator([
    new ShouldBe16CharsInLength(),
    new ShouldContainDigits(),
    new ShouldContainLetters(),
    new ShouldNotContainSpecialChars()
]);

/**
 * Test with string kdsygdbg7j6f5ps2
 * array(2) {
  ["errors"]=>
  array(0) {
  }
  ["isValid"]=>
  bool(true)
}
 */
$result = $validator->validate("kdsygdbg7j6f5ps2");
var_dump(['errors'=>$result->getErrors(), 'isValid'=>$result->isValid()]);

# 
/**
 * Test with string &(*&@(
 * Result: array(2) {
  ["errors"]=>
  array(4) {
    [0]=>
    string(33) "The string does not have 16 chars"
    [1]=>
    string(34) "The string does not contain digits"
    [2]=>
    string(35) "The string does not contain letters"
    [3]=>
    string(37) "The string does contain special chars"
  }
  ["isValid"]=>
  bool(false)
}
*/
$result = $validator->validate("&(*&@(");
var_dump(['errors'=>$result->getErrors(), 'isValid'=>$result->isValid()]);

Your code

I have changed your code to:

function create($referrer=null){
  if(preg_match('/^[a-zA-Z0-9]{16}$/', $referrer) === 1){
      echo $referrer . ': The string has 16 characters, contains digits, contains letters, and does not have any special characters.';
  }
}

Test:

create("kdsygdbg7j6f5ps2"); //kdsygdbg7j6f5ps2: The string has 16 characters, contains digits, contains letters, and does not have any special characters.
create("&(*&@("); //... nothing

CodePudding user response:

The RegEx you are looking for is ^[[:alnum:]]{16}$ that is using:

  • ^ beginning of the string
  • [:alnum:] is equivalent to a-zA-Z0-9
  • {16} matches exactly 16 characters
  • $ end of the string

Here is the code with sample testing strings:

<?php

function create($referrer=null){
  if((!empty(preg_match('/^[[:alnum:]]{16}$/', $referrer)))){
    echo PHP_EOL.'The string '.$referrer .' has 16 characters, contains digits, contains letters, and does not have any special characters.';
  }
  else{
    echo PHP_EOL.'The string '. $referrer .' does not match criteria.';
  }
}

$array = [
     'a1b2c3D4E5F6G7H8'
    ,'a1btooshort'
    ,'a1b2c3D4E5F6G7H8toolong'
    ,'!@#$%^&*()_ -=['
    ,']{};\':"\|,.<>/?'
    ,"a1b2c3D4\nE5F67H8"
];

foreach ($array as $key => $value) {
  create($value);
}

Live demo

CodePudding user response:

You can try with preg_match I did and it worked for me.

function create($referrer=null){
     $uppercase = preg_match('@[A-Z]@', $referrer);
        $lowercase = preg_match('@[a-z]@', $referrer);
        $number = preg_match('@[0-9]@', $referrer);

        if (!$uppercase) {
            echo 'Please input atleast one uppercase letter. Try again';
        } elseif (!$lowercase) {
            echo 'Please input atleast one lower case letter. Try again';
        } elseif (!$number) {
            echo 'Please input atleast one number. Try again';
        } elseif (strlen($newpassword) < 8) {
            echo 'Your password must be not less than 8 characters. Try again';
        }
}
  •  Tags:  
  • php
  • Related