Title: Bad words regex filter not working
Tags: php;regex
Question: I'm trying to get a bad words filter to work. So far, with the code below, no filtering happens if I type a bad word like "bad1" listed in array below and I get this error: 

```
  Warning: preg_match() [function.preg-match]: Unknown modifier ‘/’
```

Here is the code:

```if (isset($_POST['text'])) {

// Words not allowed
$disallowedWords = array(
'bad1',
'bad2',
);
// Search for disallowed words.
// The Regex used here should e.g. match 'are', but not match 'care'
foreach ($disallowedWords as $word) {
if (preg_match("/\s+$word\s+/i", $entry)) {
die("The word '$word' is not allowed...");
}
}

// Variable contains a regex that will match URLs

$urlRegex = '/(http|https|ftp)\://([a-zA-Z0-9\.\-]+(\:[a-zA-Z0-
9\.&amp;amp;%\$\-]+)*@)*((25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]
{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1
-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)
\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])|localhost
|([a-zA-Z0-9\-]+\.)*[a-zA-Z0-9\-]+\.
(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-z
A-Z]{2}))(\:[0-9]+)*(/($|[a-zA-Z0-9\.\,\?\'\\\+&amp;amp;%\$#\=~_\-]+))*/';

// Search for URLs
if (preg_match($urlRegex, $entry)) {
die("URLs are not allowed...");
}

}
```

Comment: `preg_quote()` for the words list. The error actually stems from unescaped `/` delimiters in the URL regex. Escape them.

Comment: I would use this regex: /\b$word\b/i, because it will match bad words at the end and at the beginning of string too, not just between words...

Comment: Why match it that way. You can check for matches with http://php.net/strpos. As to your question the regex fails because you are requiring white space on both side. You want `\s*` but then `notbadword` would also match...

Comment: You have two issues, missed the error howardsandra@example.com. That is from your delimiters. Check URL checker regex.

Here is the accepted answer: This is the right way of matching the words. Use this regex in your foreach loop.

```preg_match("#\b" . $word . "\b#", $entry);
```

You can also test your regular expressions here. Use ```/\bbad1\b/g```.

The code put in action:

```<?php
// delete the line below in your code
$entry = "notbad1word bad1 bad notbad1.";

$disallowedWords = array(
    'bad1',
    'bad2',
);

foreach ($disallowedWords as $word)
{ // use $_POST['text'] instead of $entry
    preg_match("#\b". $word ."\b#", $entry, $matches); 
    if(!empty($matches))
        die("The word " . $word . " is not allowed.");
}

echo "All good.";
```

This code doesn't match ```notbad1word``` or ```notbad2word``` (and so on) but matches only ```bad1``` or ```bad2```.

As to your urlRegex, you have to escape ```/``` with ```\``` like this: ```\/```


Here is another answer: You can do that without a slow loop: 

```<?php

$_POST['text'] = 'This sentence uses the nobad1 bad2 word!';

if (isset($_POST['text'])) {

    // Words not allowed
    $disallowedWords = array(
        'bad1',
        'bad2',
    );

    $pattern = sprintf('/(\\s%s\\s)/i', implode('\\s|\\s',$disallowedWords));
    $subject = ' '.$_POST['text'].' ';
    if (preg_match($pattern, $subject, $token)) {
        die(sprintf("The word '%s' is not allowed...\n", trim($token[1])));
    }
}
```

You have to make sure that the catalog of words does not contain any characters of ```/```, ```(``` or ```)```.  

Comment for this answer: @jvitasek And the OP said where that this should not occur?
Comment for this answer: @jvitasek Yes, but it is the OPs system, not yours. You do not know what the OP wants. At least you should not assume you do. A common mistake...
Comment for this answer: @jvitasek You are right there. Thanks for pointing that out. How good that I already added a version that considers that.
Comment for this answer: This works nicely and is much more clean and simple. Do you advise I stick the redirect to the form on the same page be added right after the die line?
Comment for this answer: I am wrong to think this is going to match `notbad1` in the string too?
Comment for this answer: A common mistake is not to read the question. It explicitly states in a comment `// The Regex used here should e.g. match 'are', but not match 'care'`

Here is another answer: You're using ```/``` as delimiting character, but don't escape its "inner" occurences:

```$urlRegex = '/(http|https|ftp)\://whatever/';
//                               ^ Unknown modifier ‘/’
```

Either change the delimiter, or escape the slashes.

As to your "bad words" filter:


It will fail to recognize words at the beginning and end of the string. Consider using ```\b``` (word boundary) instead of ```\s+```.
If any of the bad words in your array has an unescaped regex character, the results might be unexpected. Consider using ```preg_quote``` on each word from the array.
n ```preg_match``` calls for n words is not very efficient. I'd recommend imploding the words array into a single regex like ```'/\b(word1|word2|word3)\b/i'```.



{'source': 'StackExchangeDataset', 'subset': 'stackoverflow.com', 'metadata': {'AnswerCount': 3, 'CommentCount': 4, 'ContentLicense': 'CC BY-SA 3.0', 'CreationDate': '2015:00:03/21/15', 'FavoriteCount': 1.0, 'PostTypeId': 1, 'Tags': '<php><regex>', 'Title': 'Bad words regex filter not working', 'ViewCount': 915, 'id': 29188299, 'user_AboutMe': None, 'user_AccountId': 5902072.0, 'user_DisplayName': 'JA4677', 'user_Reputation': 431.0, 'user_Views': 27.0, 'user_id': 4645237.0}}