skip to Main Content

I have a simple form that needs extra validation. I have an array of banned words, which if any are present, the form submission fails.

I’ve been able to get it to work if the only word in the input is banned. However if it contains normal words and a banned word, the form submission goes through.

I do know the banned words db is working fine, as I have test code to output all of them

This is what only works if a banned term is the only word/string in there.

// array of banned words to filter; comes from DB
$disallowed_terms = Array();

$disallowed = $ww_mysqli->prepare("SELECT * FROM nl_filters");
$disallowed->bind_param('s', $Filter);
$disallowed->execute();

$s_result = $disallowed->get_result();

// check each input for banned words
while ($row = $s_result->fetch_assoc()) {
     $disallowed_terms[] = $row;

     // only wrote this for $sprequests for testing
     // strpos() doesn't seem to the right method here
     $sprequests_check = strpos($sprequests,$disallowed);

     if (in_array($sprequests_check,$row) !== false) {
        // adding anything to $reasons will cause submission to fail
         $reasons .= '|error';
      }
      if (in_array($theirname,$row) !== false) {
         $reasons .= '|error';
      }
      if (in_array($email,$row) !== false) {
         $reasons .= '|error';
      }
      if (in_array($phone,$row) !== false) {
         $reasons .= '|error';
      }
}

The current list of banned words is here

2

Answers


  1. The soloution I came up with for this problem uses the $disallowed_terms array to create a regex pattern that is then used to check each term in a users input.

    We can check each term by first removing any special characters from the input and replace it with a space and then using explode to sperate the string out into an array.

    I simplified the code for the example so the $disallowed_terms is a static asrray and the inputs are also a static array. Feel free to modify the code to match your project.

    I have left comments throughout the code explaining whats going on but if I missed something let me know :). See the code below:

    <?php
    // Example disallowed terms, you would get these from the database
    $disallowed_terms = [
        "bad",
        "evil",
        "crazy"
    ];
    
    //example inputs from the user
    $inputs = [
        "I like bad   things",
        "I like good things",
        "I like ok things",
        "I like evil, things",
        "  I like-crazy.things ",
    ];
    
    $disallowed_terms_pattern = create_disallowed_terms_regex($disallowed_terms); // get the regex that will be used
    // echo $disallowed_terms_pattern; // Outputs: /(bad|evil|crazy)/
    
    // Test each input from user and echo the result
    foreach ($inputs as $input){
    
        if(contains_disallowed_term($input,$disallowed_terms_pattern)){ // call function to check if input contains disallowed term
           // disallowed term found
            echo "NOT GOOD -".$input."<br>";
        }else{
            // disallowed term NOT found
            echo "OK -". $input."<br>";
        }
    }
    
    /* SAMPLE OUTPUT:
        NOT GOOD -I like bad things
        OK -I like good things
        OK -I like ok things
        NOT GOOD -I like evil, things
        NOT GOOD - I like-crazy.things
    */
    
    // create regex pattern string that will contain all the disallowed terms eg. Outputs: /(bad|evil|crazy)/
    function create_disallowed_terms_regex($disallowed_terms){
        $regex = '/(';
        foreach ($disallowed_terms as $term){
            $regex.=$term.'|';
        }
    
        $regex = rtrim($regex,'|'); // remove | from end of string
    
        $regex .= ')/';
    
        return $regex;
    }
    
    function contains_disallowed_term($input,$disallowed_terms_pattern){
    
        // Replace all special characters with spaces, this stops inputs like i'am-not-crazy;) from getting passed the regex
        $input = preg_replace('/[^ws]/', ' ', $input);
    
        $input_terms = explode(" ", $input); // explode the input string into an array using spaces as a seperator
    
        foreach ($input_terms as $term){ // go over each term in the input
            if(preg_match($disallowed_terms_pattern, $term)){
                return true; // if it matches a word in disallowed list return true;
            }
        }
        
        //term didn't match disallowed term, return false
        return false;
    }
    
    ?>
    

    The obvious limitation to this solution is it won’t be able to detect words like ‘cr*zy’ because it removes the * and replaces it with a space. On the flip side it will detect the word crazy in sting like this ‘.:thats-crazy:.’.

    If some of the disallowed words contain special characters the solution may need modifaction as well. As the create_disallowed_terms_regex() function could break and words with special characters would never be detected because the solution strips special characters out of the input. Both issues can be mitigated with minor changes.

    Login or Signup to reply.
  2. You can try this:

    1. Use stripos() so the search is case-insensitive.

    2. Use $row[‘filter’] assuming filter is the column name in the database, instead of $disallowed in the stripos check.

      // array of banned words to filter; comes from DB
      
      $disallowed_terms = [];
      
      $disallowed = $ww_mysqli->prepare("SELECT * FROM nl_filters");
      $disallowed->execute();
      
      $s_result = $disallowed->get_result();
      
      // check each input for banned words
      
      while ($row = $s_result->fetch_assoc()) {
      
          $disallowed_terms[] = $row['filter']; // Assuming 'filter' is the column name in your database
      
          // Check if any banned words are present in each input
          if (containsBannedWord($sprequests, $disallowed_terms)) {
              $reasons .= '|error';
          }
          if (containsBannedWord($theirname, $disallowed_terms)) {
              $reasons .= '|error';
          }
          if (containsBannedWord($email, $disallowed_terms)) {
              $reasons .= '|error';
          }
          if (containsBannedWord($phone, $disallowed_terms)) {
              $reasons .= '|error';
          }
      }
      
      function containsBannedWord($input, $bannedWords) {
          foreach ($bannedWords as $bannedWord) {
              // Use stripos for case-insensitive check
              if (stripos($input, $bannedWord) !== false) {
                 return true;
              }
          }
          return false;
      }
      

    The function ‘containsBannedWord’ checks if any banned word is present in the input.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search