How do I deny some keywords on user input - php
Example user input that should be denied:
House for sale
Car for rent
WTB iphone with cheap price
How do I make my code deny inputs like those above?
$title = array('rent','buy','sale','sell','wanted','wtb','wts');
$user_title = stripslashes($_POST['title']);
if (in_array($user_title, $title)) {
$error = '<p class="error">Do not include ' . $user_title . ' on your title</p>';
}
If you want your denied words to be complete words and not just part of another word for it to be considered denied, you can use a regex based solution with word boundaries:
// array of denied words.
$deniedWords = array('rent','buy','sale','sell','wanted','wtb','wts');
// run preg_quote on each array element..as it may have a regex meta-char in it.
$deniedWords = array_map('preg_quote',$deniedWords);
// construct the pattern as /(\bbuy\b|\bsell\b...)/i
$pat = '/(\b'.implode('\b|\b',$deniedWords).'\b)/i';
// use preg-match_all to find all matches
if(preg_match_all($pat,$user_title,$matches)) {
// $matches[1] has all the found word(s), join them with comma and print.
$error = 'Do not include ' . implode(',',$matches[1]);
}
Ideone Link
You can use stripos():
$title = array('rent','buy','sale','sell','wanted','wtb','wts');
$user_title = stripslashes($_POST['title']);
foreach($title as $word)
{
if (stripos($user_title, $word) !== false)
{
$error = '<p class="error">Do not include ' . $word . ' on your title</p>';
break;
}
}
You can also use regex:
if (preg_match("/(rent|buy|sale|sell|wanted|wtb|wts)/is", $user_title)) {
$error = '<p class="error">Do not include ' . $user_title . ' on your title</p>';
}
You can utilize explode() in order to separate the words in $user_title and check each one to ensure it does not exist in $title.
$invalidWords = '';
$words = explode(' ', stripslashes($_POST['title']));
foreach($words as $word) {
if (in_array($word, $title)) {
$invalidWords .= ' ' . $word;
}
}
if (!empty($invalidWords)) {
echo '<p class="error">Do not include the following words in your title: ' . $invalidWords . '</p>';
}
RegEx is probably best, but off-hand I cannot easily figure out the expression required in order for you to be able to output all of the invalid words in a list to the user.
Related
how can i ban specific numbers from a .txt file?
I made a text file named ben.txt and there are some numbers line by line, for example 123456 so i want, whenever someone type !check 123456 so they should get message like Number Banned I Made a code But it doesn't working My Code $been = file_get_contents(ben.txt); $isbanned = false; foreach ($been as $bb) { if(strpos($message, "!sa $bb") ===0) $isbanned = true; sendMessage($chatId, "<b>Number Banned!</b>"); return; }
You can turn the contents of the file into a regular expression that matches any of the strings. $ex_cont = file("ben.txt", FILE_IGNORE_NEW_LINES); $isbanned = false; $regex = '/^!sa (' . implode('|', array_map('preg_quote', $ex_cont)) . ')/'; if (preg_match($regex, $message)) { $isbanned = true; sendMessage($chatId, "<b>Number Banned!</b>"); }
Unexpected result using OR operator in regular expression
I've a problem with a regular expression. I have a text which is read from a file. The text can contain one or more IDs separated by comma. And then I have a list of IDs and want to check if one of these IDs match with my text so I try to use an OR operator: $idString = '2561,3,261,6,540,33,3105,2085,38,42,1066,49,3377,53,3161,91,356,3179,3695,3184,370,123,3451,124,3710,2188,141,404,1435,160,1443,432,435,440,1721,3261,2498,205,3282,476,482,3301,486,749,3309,243,3059,759,2046,4,262,785,534,541,3360,34,3106,2086,39,43,50,3378,54,1337,61,1351,3157,3162,360,3696,3185,631,3450,3200,666,1436,673,1444,3748,3262,2499,206,3279,3283,470,477,483,3302,490,755,760,2047,2562,1029,263,23,542,35,3107,2087,40,552,553,1321,47,51,3379,55,1338,3163,361,3697,3186,633,3452,639,143,3223,1445,3749,1450,3263,2500,207,3284,478,484,3303,2559,264,1297,22,543,36,44,57,1339,3389,62,3164,3677,362,3180,634,144,1685,1446,430,700,208,3286,479,1249,485,3306,2558,255,265,524,30,288,46,2095,63,2375,3165,403,1447,3242,696,1724,3557,3304,1770,3066,2563,266,544,2338,555,3131,3166,2204,415,1448,1239,3288,480,3305,754,267,545,3370,2378,3152,3170,648,147,679,1449,2537,753,2546,505,2564,3335,268,535,537,539,546,549,65,69,3167,148,3244,744,3068,2565,269,286,547,292,1334,1340,3659,3168,383,153,1705,3267,3060,2566,270,271,3099,548,1660,398,154,1706,2511,746,3332,2568,272,3148,422,3269,752,768,273,3381,3153,3199,155,468,784,274,3093,325,1657,3319,510,3329,3333,275,1432,2230,441,1722,773,3338,276,3641,2108,491,3339,277,2398,107,3181,2245,757,3346,2100,619,1760,2050,3351,2103,667,19,3372,2534,1064,351,1726,2394,2508,2538,2104,3147,2083,2097,2042,2096,2165,2049,2525,2526,1774,2392,2080,2043,2542,2547,2129,2540,2536,2190,2226,2569,2572,2373,2507'; $idString = str_replace(',', '|', $idString); $text = '1453,2018'; if (preg_match('/' . $idString . '/', $text)) { echo 'yes' . PHP_EOL; } else { echo 'no' . PHP_EOL; } I'm expecting that nothing matches because the IDs 1453 and 2018 are not found in my lookup string but it matches. I think that's because the ID 3 matches with 1453 but this is not correct for my use case.
That's too easy to work around it using arrays. You shouldn't use Regular Expressions if you can work with them but it seems this is not your real problem but an MCVE for a different one. You should use word boundaries \b otherwise a number like 4 is found in 1453. preg_match() third argument holds results to analyze what is going on. preg_match('/\b(?:' . $idString . ')\b/', $text, $match)
The syntax for preg_match is ($pattern, $text). Change it as follows, worked for me. <?php $idString = '2561,3,261,6,540,33,3105,2085,38,42,1066,49,3377,53,3161,91,356,3179,3695,3184,370,123,3451,124,3710,2188,141,404,1435,160,1443,432,435,440,1721,3261,2498,205,3282,476,482,3301,486,749,3309,243,3059,759,2046,4,262,785,534,541,3360,34,3106,2086,39,43,50,3378,54,1337,61,1351,3157,3162,360,3696,3185,631,3450,3200,666,1436,673,1444,3748,3262,2499,206,3279,3283,470,477,483,3302,490,755,760,2047,2562,1029,263,23,542,35,3107,2087,40,552,553,1321,47,51,3379,55,1338,3163,361,3697,3186,633,3452,639,143,3223,1445,3749,1450,3263,2500,207,3284,478,484,3303,2559,264,1297,22,543,36,44,57,1339,3389,62,3164,3677,362,3180,634,144,1685,1446,430,700,208,3286,479,1249,485,3306,2558,255,265,524,30,288,46,2095,63,2375,3165,403,1447,3242,696,1724,3557,3304,1770,3066,2563,266,544,2338,555,3131,3166,2204,415,1448,1239,3288,480,3305,754,267,545,3370,2378,3152,3170,648,147,679,1449,2537,753,2546,505,2564,3335,268,535,537,539,546,549,65,69,3167,148,3244,744,3068,2565,269,286,547,292,1334,1340,3659,3168,383,153,1705,3267,3060,2566,270,271,3099,548,1660,398,154,1706,2511,746,3332,2568,272,3148,422,3269,752,768,273,3381,3153,3199,155,468,784,274,3093,325,1657,3319,510,3329,3333,275,1432,2230,441,1722,773,3338,276,3641,2108,491,3339,277,2398,107,3181,2245,757,3346,2100,619,1760,2050,3351,2103,667,19,3372,2534,1064,351,1726,2394,2508,2538,2104,3147,2083,2097,2042,2096,2165,2049,2525,2526,1774,2392,2080,2043,2542,2547,2129,2540,2536,2190,2226,2569,2572,2373,2507'; $idString = str_replace(',', '|', $idString); $text = '1453,2018'; if (preg_match('/(' . $text . ')/', $idString)) { echo 'yes' . PHP_EOL; } else { echo 'no' . PHP_EOL; } ?>
You can see what gets matched by your Regex by outputting the matches, eg: if (preg_match('/' . $idString . '/', $text, $matches)) { echo 'yes' . PHP_EOL; print_r($matches); } else { echo 'no' . PHP_EOL; } You'd have to adapt your regex to match against whole words only... for example like this: if (preg_match('/\b(' . $idString . ')\b/', $text)) { https://regex101.com/r/M1Pieb/2/ Or you could avoid using regex altogether (recommended, its getting a bit crazy..) by using explode $idString = '2561,3,261,6,540,33,3105,2085,38,42,1066,49,3377,53,3161,91,356,3179,3695,3184,370,123,3451,124,3710,2188,141,404,1435,160,1443,432,435,440,1721,3261,2498,205,3282,476,482,3301,486,749,3309,243,3059,759,2046,4,262,785,534,541,3360,34,3106,2086,39,43,50,3378,54,1337,61,1351,3157,3162,360,3696,3185,631,3450,3200,666,1436,673,1444,3748,3262,2499,206,3279,3283,470,477,483,3302,490,755,760,2047,2562,1029,263,23,542,35,3107,2087,40,552,553,1321,47,51,3379,55,1338,3163,361,3697,3186,633,3452,639,143,3223,1445,3749,1450,3263,2500,207,3284,478,484,3303,2559,264,1297,22,543,36,44,57,1339,3389,62,3164,3677,362,3180,634,144,1685,1446,430,700,208,3286,479,1249,485,3306,2558,255,265,524,30,288,46,2095,63,2375,3165,403,1447,3242,696,1724,3557,3304,1770,3066,2563,266,544,2338,555,3131,3166,2204,415,1448,1239,3288,480,3305,754,267,545,3370,2378,3152,3170,648,147,679,1449,2537,753,2546,505,2564,3335,268,535,537,539,546,549,65,69,3167,148,3244,744,3068,2565,269,286,547,292,1334,1340,3659,3168,383,153,1705,3267,3060,2566,270,271,3099,548,1660,398,154,1706,2511,746,3332,2568,272,3148,422,3269,752,768,273,3381,3153,3199,155,468,784,274,3093,325,1657,3319,510,3329,3333,275,1432,2230,441,1722,773,3338,276,3641,2108,491,3339,277,2398,107,3181,2245,757,3346,2100,619,1760,2050,3351,2103,667,19,3372,2534,1064,351,1726,2394,2508,2538,2104,3147,2083,2097,2042,2096,2165,2049,2525,2526,1774,2392,2080,2043,2542,2547,2129,2540,2536,2190,2226,2569,2572,2373,2507'; $idStrings = explode(',', $idString); $values = ['1453', '2018']; $matchedValue = null; foreach ($values as $value) { if (in_array($value, $idStrings)) { $matchedValue = $value; break; } } if ($matchedValue !== null) { echo 'yes: ' . $matchedValue; } else { echo 'no'; }
Reformat a text file in PHP
I want to reformat a text file from this: • Name - 5 September 12:19 - Message To this: Name (5 September, 12:19) Message Where the names are in bold text and it may be some indications that steps forward in the messages (-- -- -- --). These indications will be replaces with a <hr>. You can see the whole text file here. I have came up with this: $url = 'http://erik-edgren.nu/files/history/apg29/jesus-september-2014.txt'; $lines = file($url, FILE_IGNORE_NEW_LINES); foreach($lines AS $line) { $info = explode(' - ', $line); if(strlen($info[0]) > '• ') { echo '<b>'.str_replace('• ', '', $info[0]).'</b>'; } echo !isset($info[1]) ? '' : ' ('.$info[1].')'; echo '<br>'; } But I don't know how I can reformat the document as I want in the best way possible. Any solution on how I can accomplish this?
This is the basic idea of what I would do. You probably need to replace '•' with unicode for that character. This script does not probably work, but it has the general idea of what I would do. <?php $url = 'http://erik-edgren.nu/files/history/apg29/jesus-september-2014.txt'; $thedata=file_get_contents($url); $lines=explode(PHP_EOL,$thedata); $line1=''; foreach($lines as $a) { if(substr($a,2,2)=='• ') { $data=explode(' ',$a); $line1=$data[1] . ' (' . $data[3] . ' ' . $data[4] . ', ' . $data[5] . ')'.PHP_EOL; } if(substr($a,2,2)=='- ') { echo $line1 . substr($a,2) . PHP_EOL; } } ?>
ucwords function with exceptions
I need some help i have this code that Uppercase the first character of each word in a string with exceptions i need the function to ignore the exception if it's at the beginning of the string: function ucwordss($str, $exceptions) { $out = ""; foreach (explode(" ", $str) as $word) { $out .= (!in_array($word, $exceptions)) ? strtoupper($word{0}) . substr($word, 1) . " " : $word . " "; } return rtrim($out); } $string = "my cat is going to the vet"; $ignore = array("is", "to", "the"); echo ucwordss($string, $ignore); // Prints: My Cat is Going to the Vet this is what im doing: $string = "my cat is going to the vet"; $ignore = array("my", "is", "to", "the"); echo ucwordss($string, $ignore); // Prints: my Cat is Going to the Vet // NEED TO PRINT: My Cat is Going to the Vet
- return rtrim($out); + return ucfirst(rtrim($out));
Something like this: function ucwordss($str, $exceptions) { $out = ""; foreach (explode(" ", $str) as $key => $word) { $out .= (!in_array($word, $exceptions) || $key == 0) ? strtoupper($word{0}) . substr($word, 1) . " " : $word . " "; } return rtrim($out); } Or even easier, before return in your function make strtoupper first letter
Do this really cheaply by just always uppercasing your first word: function ucword($word){ return strtoupper($word{0}) . substr($word, 1) . " "; } function ucwordss($str, $exceptions) { $out = ""; $words = explode(" ", $str); $words[0] = ucword($words[0]); foreach ($words as $word) { $out .= (!in_array($word, $exceptions)) ? ucword($word) : $word . " "; } return rtrim($out); }
what about you make the first letter in the string upper case so no matter your mix you will still come through $string = "my cat is going to the vet"; $string = ucfirst($string); $ignore = array("is", "to", "the"); echo ucwordss($string, $ignore); this way you first letter of the string will always be upper case
preg_replace_callback() will allow you to express your conditional replacement logic in a loopless and dynamic fashion. Consider this approach that will suitably modify your sample data: Code: (PHP Demo) (Pattern Demo) $string = "my cat is going to the vet"; $ignore = array("my", "is", "to", "the"); $pattern = "~^[a-z]+|\b(?|" . implode("|", $ignore) . ")\b(*SKIP)(*FAIL)|[a-z]+~"; echo "$pattern\n---\n"; echo preg_replace_callback($pattern, function($m) {return ucfirst($m[0]);}, $string); Output: ~^[a-z]+|\b(?|my|is|to|the)\b(*SKIP)(*FAIL)|[a-z]+~ --- My Cat is Going to the Vet You see, the three piped portions of the pattern (in order) make these demands: If the start of the string is a word, capitalize the first letter. If a "whole word" (leveraging the \b word boundary metacharacter) is found in the "blacklist", disqualify the match and keep traversing the input string. Else capitalize the first letter of every word. Now, if you want to get particular about contractions and hyphenated words, then you only need to add ' and - to the [a-z] character classes like this: [a-z'-] (Pattern Demo) If anyone has a fringe cases that will break my snippet (like "words" with special characters that need to be escaped by preg_quote()), you can offer them and I can offer a patch, but my original solution will adequately serve the posted question.
How to wrap user mentions in a HTML link on PHP?
Im working on a commenting web application and i want to parse user mentions (#user) as links. Here is what I have so far: $text = "#user is not #user1 but #user3 is #user4"; $pattern = "/\#(\w+)/"; preg_match_all($pattern,$text,$matches); if($matches){ $sql = "SELECT * FROM users WHERE username IN ('" .implode("','",$matches[1]). "') ORDER BY LENGTH(username) DESC"; $users = $this->getQuery($sql); foreach($users as $i=>$u){ $text = str_replace("#{$u['username']}", "<a href='#' class='ct-userLink' rel='{$u['user_id']}'>#{$u['username']}</a> ", $text); } $echo $text; } The problem is that user links are being overlapped: <a rel="11327" class="ct-userLink" href="#"> <a rel="21327" class="ct-userLink" href="#">#user</a>1 </a> How can I avoid links overlapping? Answer Update Thanks to the answer picked, this is how my new foreach loop looks like: foreach($users as $i=>$u){ $text = preg_replace("/#".$u['username']."\b/", "<a href='#' title='{$u['user_id']}'>#{$u['username']}</a> ", $text); }
Problem seems to be that some usernames can encompass other usernames. So you replace user1 properly with <a>user1</a>. Then, user matches and replaces with <a><a>user</a>1</a>. My suggestion is to change your string replace to a regex with a word boundary, \b, that is required after the username.
The Twitter widget has JavaScript code to do this. I ported it to PHP in my WordPress plugin. Here's the relevant part: function format_tweet($tweet) { // add #reply links $tweet_text = preg_replace("/\B[#@]([a-zA-Z0-9_]{1,20})/", "#<a class='atreply' href='http://twitter.com/$1'>$1</a>", $tweet); // make other links clickable $matches = array(); $link_info = preg_match_all("/\b(((https*\:\/\/)|www\.)[^\"\']+?)(([!?,.\)]+)?(\s|$))/", $tweet_text, $matches, PREG_SET_ORDER); if ($link_info) { foreach ($matches as $match) { $http = preg_match("/w/", $match[2]) ? 'http://' : ''; $tweet_text = str_replace($match[0], "<a href='" . $http . $match[1] . "'>" . $match[1] . "</a>" . $match[4], $tweet_text); } } return $tweet_text; }
instead of parsing for '#user' parse for '#user ' (with space in the end) or ' #user ' to even avoid wrong parsing of email addresses (eg: mailaddress#user.com) maybe ' #user: ' should also be allowed. this will only work, if usernames have no whitespaces...
You can go for a custom str replace function which stops at first replace.. Something like ... function str_replace_once($needle , $replace , $haystack){ $pos = strpos($haystack, $needle); if ($pos === false) { // Nothing found return $haystack; } return substr_replace($haystack, $replace, $pos, strlen($needle)); } And use it like: foreach($users as $i=>$u){ $text = str_replace_once("#{$u['username']}", "<a href='#' class='ct-userLink' rel='{$u['user_id']}'>#{$u['username']}</a> ", $text); }
You shouldn’t replace one certain user mention at a time but all at once. You could use preg_split to do that: // split text at mention while retaining user name $parts = preg_split("/#(\w+)/", $text, -1, PREG_SPLIT_DELIM_CAPTURE); $n = count($parts); // $n is always an odd number; 1 means no match found if ($n > 1) { // collect user names $users = array(); for ($i=1; $i<$n; $i+=2) { $users[$parts[$i]] = ''; } // get corresponding user information $sql = "SELECT * FROM users WHERE username IN ('" .implode("','", array_keys($users)). "')"; $users = array(); foreach ($this->getQuery($sql) as $user) { $users[$user['username']] = $user; } // replace mentions for ($i=1; $i<$n; $i+=2) { $u = $users[$parts[$i]]; $parts[$i] = "<a href='#' class='ct-userLink' rel='{$u['user_id']}'>#{$u['username']}</a>"; } // put everything back together $text = implode('', $parts); }
I like dnl solution of parsing ' #user', but maybe is not suitable for you. Anyway, did you try to use strip_tags function to remove the anchor tags? That way you have the string without the links, and you can parse it building the links again. strip_tags