I have a pattern with a small list of words that are illegal to use as nicknames set in a pattern variable like this:
$pattern = webmaster|admin|webadmin|sysadmin
Using preg_match, how can I achieve so that nicknames with these words are forbidden, but registering something like "admin2" or "thesysadmin" is allowed?
This is the expression I have so far:
preg_match('/^['.$pattern.']/i','admin');
// Should not be allowed
Note: Using a \b didn't help much.
What about not using regex at all ?
And working with explode and in_array ?
For instance, this would do :
$pattern = 'webmaster|admin|webadmin|sysadmin';
$forbidden_words = explode('|', $pattern);
It explodes your pattern into an array, using | as separator.
And this :
$word = 'admin';
if (in_array($word, $forbidden_words)) {
echo "<p>$word is not OK</p>";
} else {
echo "<p>$word is OK</p>";
}
will get you
admin is not OK
Whereas this (same code ; only the word changes) :
$word = 'admin2';
if (in_array($word, $forbidden_words)) {
echo "<p>$word is not OK</p>";
} else {
echo "<p>$word is OK</p>";
}
will get you
admin2 is OK
This way, no need to worry about finding the right regex, to match full-words : it'll just match exact words ;-)
Edit : one problem might be that the comparison will be case-sensitive :-(
Working with everything in lowercase will help with that :
$pattern = strtolower('webmaster|admin|webadmin|sysadmin'); // just to be sure ;-)
$forbidden_words = explode('|', $pattern);
$word = 'aDMin';
if (in_array(strtolower($word), $forbidden_words)) {
echo "<p>$word is not OK</p>";
} else {
echo "<p>$word is OK</p>";
}
Will get you :
aDMin is not OK
(I saw the 'i' flag in the regex only after posting my answer ; so, had to edit it)
Edit 2 : and, if you really want to do it with a regex, you need to know that :
^ marks the beginning of the string
and $ marks the end of the string
So, something like this should do :
$pattern = 'webmaster|admin|webadmin|sysadmin';
$word = 'admin';
if (preg_match('#^(' . $pattern . ')$#i', $word)) {
echo "<p>$word is not OK</p>";
} else {
echo "<p>$word is OK</p>";
}
$word = 'admin2';
if (preg_match('#^(' . $pattern . ')$#i', $word)) {
echo "<p>$word is not OK</p>";
} else {
echo "<p>$word is OK</p>";
}
Parentheses are probably not necessary, but I like using them, to isolate what I wanted.
And, you'll get the same kind of output :
admin is not OK
admin2 is OK
You probably don't want to use [ and ] : they mean "any character that is between us", and not "the whole string that is between us".
And, as the reference : manual of the preg syntax ;-)
So, the forbidden words can be part of their username but not the whole thing?
In .NET, the pattern would be:
Allowed = Not RegEx.Match("admin", "^(webmaster|admin|webadmin|sysadmin)$")
The "^" matches the beginning of the string, the "$" matches the end, so it's looking for an exact match on one of those words. I'm a bit fuzzy on the corresponding PHP syntax.
Related
I have urls on my site like:
http://example.com/item/one/
http://example.com/item/two/
http://example.com/item/one/something
http://example.com/item/two/someotherthing
http://example.com/other/one/
http://example.com/other/two/
And I want to check the url and redirect if it matches /item/one/ or /item/two/ but NOT if it matches just /one/ or /two/, and NOT matching any string that goes deeper like something.
Ideally, I would want to match anything that contains both /item/ and one final path after that (ie /item/three/,/item/four/ as well).
What would be the best way to accomplish the match? preg_match (not sure how to write it for this)? explode?
UPDATE
Tried the following:
$thisurl = $_SERVER['REQUEST_URI'];
if (preg_match("/^\/item\/(.*)\/$/", $thisurl)) {
echo "it matches";
} else {
echo "nope nope nope";
}
Which works in this tester, but fails in my code (because it also matches true for things like:
http://example.com/item/one/something
http://example.com/item/two/someotherthing
which it should not.
This regex does the job:
~/item/[^/]+/$~i
Explanation:
~ : regex delimiter
/item/ : literally
[^/]+ : 1 or more character that is NOT a slash
/ : a slash
$ : end of string
~i : regex delimiter + case insensitive
In use:
$tests = array(
'http://example.com/item/one/',
'http://example.com/item/two/',
'http://example.com/item/one/something',
'http://example.com/item/two/someotherthing',
'http://example.com/other/one/',
'http://example.com/other/two/'
);
foreach($tests as $test) {
echo "$test --> ";
if (preg_match('~/item/[^/]+/$~i', $test)) {
echo "valid\n";
} else {
echo "invalid\n";
}
}
Output:
http://example.com/item/one/ --> valid
http://example.com/item/two/ --> valid
http://example.com/item/one/something --> invalid
http://example.com/item/two/someotherthing --> invalid
http://example.com/other/one/ --> invalid
http://example.com/other/two/ --> invalid
This is how you could do it using the explode function.
$url = [
'http://example.com/item/one/',
'http://example.com/item/two/',
'http://example.com/item/one/something',
'http://example.com/item/two/someotherthing',
'http://example.com/other/one/',
'http://example.com/other/two/'
];
foreach($url as $row){
$path = explode('/',str_replace('http://example.com/','',rtrim($row,'/')));
if(count($path) != 2){
continue;
}
if($path[0] != "item"){
continue;
}
if(in_array($path[1],[
'one',
'two'
])){
echo 'redirect...';
}
}
However a better answer would probably involve using some form of regex.
Finally got it working with this:
if (preg_match("/^\/item\/[-a-z]+\/$/", $thisurl)) { //matches any lowercase word that may or may not contain a dash
echo "it matches";
} else {
echo "nope nope nope";
}
DESPITE this page telling me that preg_match("/^\/item\/(.*)\/$/", $thisurl) would work, it did not.
I am checking username entered by user
I'm trying to validate usernames in PHP using preg_match() but I can't seem to get it working the way I want it. I require preg_match() to:
accept only letters , numbers and . - _
i.e. alphanumeric dot dash and underscore only, i tried regex from htaccess which is like this
([A-Za-z0-9.-_]+)
like this way but it doesnt seem to work, it giving false for simple alpha username.
$text = 'username';
if (preg_match('/^[A-Za-z0-9.-_]$/' , $text)) {
echo 'true';
} else {
echo 'false';
}
How can i make it work ?
i am going to use it in function like this
//check if username is valid
function isValidUsername($str) {
return preg_match('/[^A-Za-z0-9.-_]/', $str);
}
i tried answwer in preg_match() and username but still something is wrong in the regex.
update
I am using code given by xdazz inside function like this.
//check if username is valid
function isValidUsername($str) {
if (preg_match('/^[A-Za-z0-9._-]+$/' , $str)) {
return true;
} else {
return false;
}
}
and checking it like
$text = 'username._-546_546AAA';
if (isValidUsername($text) === true) {
echo 'good';
}
else{
echo 'bad';
}
You missed the +(+ for one or more, * for zero or more), or your regex only matches a string with one char.
if (preg_match('/^[A-Za-z0-9._-]+$/' , $text)) {
echo 'true';
} else {
echo 'false';
}
hyphen - has special meaning inside [...] that is used for range.
It should be in the beginning or in the last or escape it like ([A-Za-z0-9._-]+) otherwise it will match all the character that is in between . and _ in ASCII character set.
Read similar post Including a hyphen in a regex character bracket?
Better use \w that matches [A-Za-z0-9_]. In shorter form use [\w.-]+
What is the meaning for your last regex pattern?
Here [^..] is used for negation character set. If you uses it outside the ^[...] then it represents the start of the line/string.
[^A-Za-z0-9.-_] any character except:
'A' to 'Z',
'a' to 'z',
'0' to '9',
'.' to '_'
Just put - at the last in character class and add + after the char class to match one or more characters.
$text = 'username';
if (preg_match('/^[A-Za-z0-9._-]+$/' , $text)) {
echo 'true';
} else {
echo 'false';
}
function should be like this
function isValidUsername($str) {
return preg_match("/^[A-Za-z0-9._-]+$/", $str);
}
<?php
$flag=true;
if(isset($_POST['sub'])){
if(isset($_POST['text'])){
$a=$_POST["text"];
} else {
$a='';
}
if(!empty($_POST['msg'])){
$b=$_POST['msg'];
$c=strlen($b);}
if(isset($_POST['wrd'])){
$d=($_POST["wrd"]);
} else {
$d='';
}
if(preg_match("[\w\s.,a-zA-Z$a,\.]",$b)){
$flag=false;
}
if($flag){
$i;
for($i=0;$i<=$c;$i++)
{
$newtext = str_replace($a,$d,$b);
echo $newtext;
echo "</br>";
break;
}
} else {
echo"not found ";}
}
?>
This is my code I want to match word(paragraph) from a original paragraph but the problem is this.
In one line the word (paragraph) is written like this (paragraph,) and (paragraph.)
That's why preg_match is not able to find the these two word and same goes to preg_replace also.
This is incorrect:
if(preg_match("[\w\s.,a-zA-Z$a,\.]",$b))
Regex needs start and end delimiters. It should be:
if(preg_match("/[\w\s.,a-zA-Z$a,\.]/", $b))
Also note that your regex is also incorrect. I can see few mistakes (there myay be more):
inside square brackets you don't need to escape dot
you seem to have another dot that will match ANY character
You have \w that means word character hence you don't need separate a-zA-Z
You have a misplaced a after $ sign
So I get how to replace certain words with other ones. What I'm trying to figure out is how to take a word and replace it with a phrase and eliminate all other input.
For example:
bad word is 'dog'
user inputs -> 'You smell like a dog.'
instead of it replacing 'dog' with 'rainbow' or something, I want it to echo something like: 'You are a potty mouth'.
Here's what I have for code:
<?php
$find = array('dog', 'cat', 'bird');
$replace = 'You are a potty mouth.';
if (isset ($_POST['user_input'])&&!empty($_POST['user_input'])) {
$user_input = $_POST['user_input'];
$user_input_new = str_ireplace($find, $replace, $user_input);
echo $user_input_new;
}
?>
With this code it echos: 'You smell like a You are a pottymouth.'
I'm sure this is a repost and I apologize. Everything I've been able to find is documentation on how to replace only parts of strings, not entire ones.
Well, in this case you can just check whether there is a "bad word" in the user input string, and if it returns true, echo "You are a potty mouth."
You would want to use strpos()
e.g.
if( strpos($_POST['user_input'],'dog')!==FALSE ) {
echo('You are a potty mouth');
}
If you have an array of "bad words" you'll want to loop through them to check any occur within user input.
I've been looking at the same issue recently, here's a script I was working on to filter certain words. Still a work in progress but it has the ability to output the user message or a custom message. Hope it helps or points you in the right direction.
define("MIN_SAFE_WORD_LIMIT", 3);
$safe = true;
$whiteList = array();
$blackList = array();
$text = 'Test words fRom a piece of text.';
$blCount = count($blackList);
for($i=0; $i<$blCount; $i++) {
if((strlen($blackList[$i]) >= MIN_SAFE_WORD_LIMIT) && strstr(strtolower($text), strtolower($blackList[$i])) && !strstr(strtolower($text), strtolower($whiteList[$i]))) {
$safe = false;
}
}
if(!$safe) {
// Unsafe, flag for action
echo 'Unsafe';
} else {
echo $text;
}
You don't want to replace the bad words, but the whole string, so you should just match and if matched set the whole string to your replacement string.
Also, as pointed out in the comments the words can be part of another, valid, word so if you want to take that into account, you should match only whole words.
This simple example uses word boundaries in a regular expression to match your words (in the example this would be in a loop, looping over your bad words array):
foreach ($find as $your_word)
{
$search = '/\b' . preg_quote($your_word) . '\b/i';
if (preg_match($search, $_POST['user_input']) === 1)
{
// a match is found, echo or set it to a variable, whatever you need
echo $replace;
// break out of the loop
break;
}
}
Heres an alternative solution, match words and replace with * len of str. this wont match words like Scunthorpe as it uses word boundaries, Also you you can add a 3rd param to reveal the first letters of the word so you know what word was said without seeing it.
<?php
$badwords = array('*c word', '*f word','badword','stackoverflow');
function swear_filter($str,$badwords,$reveal=null) {
//Alternatively load from file
//$words = join("|", array_filter(array_map('preg_quote',array_map('trim', file('badwords.txt')))));
$words = join("|", array_filter(array_map('preg_quote',array_map('trim', $badwords))));
if($reveal !=null && is_numeric($reveal)){
return preg_replace("/\b($words)\b/uie", '"".substr("$1",0,'.$reveal.').str_repeat("*",strlen("$1")-'.$reveal.').""', $str);
}else{
return preg_replace("/\b($words)\b/uie", '"".str_repeat("*",strlen("$1")).""', $str);
}
}
$str="There was a naughty Peacock from Scunthorpe and it said a badword, on stackoverflow";
//There was a naughty Peacock from Scunthorpe and it said a b******, on s************
echo swear_filter($str,$badwords,1);
//There was a naughty Peacock from Scunthorpe and it said a *******, on *************
echo swear_filter($str,$badwords);
?>
I have a part of a function that goes like this:
if (preg_match("#\bscript\b#",$userInput))
{
$bannedWord = 'script';
logHax();
return TRUE;
}
This is causing a problem for what I am trying to accomplish because it will only match the exact word "script" and not variations of it, like "ScriPt" or "<script>".
What I would like to have is the examples of the not matched strings along with the original string return true.
How's this:
if (preg_match("/<script\b[^>]*>/i",$userInput))
{
$bannedWord = 'script';
logHax();
return TRUE;
}
Case-insensitive matching:
preg_match("#\bscript\b#i",$userInput)
Note the i. Also note that this the first example in the docs:
<?php
// The "i" after the pattern delimiter indicates a case-insensitive search
if (preg_match("/php/i", "PHP is the web scripting language of choice.")) {
echo "A match was found.";
} else {
echo "A match was not found.";
}
?>
Cheers
If you really want to match "anything" before or after the string (not just a word), then you do not even need preg_match here, bacuse you could do something like this:
$userInputLower = strtolower($userInput);
if (strpos($userInputLower, 'script') !== false)
{
$bannedWord = 'script';
logHax();
return TRUE;
}