I have a text file : ban.txt have content
a:5:{i:14528;s:15:" 118.71.102.176";i:6048;s:15:" 113.22.109.137";i:16731;s:3:" 118.71.102.76";i:2269;s:12:" 1.52.251.63";i:9050;s:14:"123.21.100.174";}
I write a script to find and ban IP in this txt
<?php
$banlist = file("ban.txt");
foreach($banlist as $ips ) {
if($_SERVER["REMOTE_ADDR"] == $ips) {
die("Your IP is banned!");
}
}
?>
Can help me to list IP in this content, i m a newbie php. Thanks very much
Look this is an acknowledged crap solution based on an unclear question
Regex never seems a great solution, but I don't have a lot of detail on how consistent the file is.
1. Isolate "s" segments in your ban.txt
As such, and my regex isn't fantastic, but this regex should match the "s" segments which appear to be for IP bans (although your comment stating "The IP always in "ip"" confuses this a little).
Regex: s:[0-9]+:"[ ]*[0-9]+.[0-9]+.[0-9]+.[0-9]+";
2. Isolate the IPs within each "s" segment
Once we have these segments, we can strip the start bit up to the actual IP (i.e. turn s:123:"192.168.0.0"; into 192.168.0.0";), and afterwards trim the end quotation mark and semi-colon (i.e. 192.168.0.0"; to 192.168.0.0):
Regex for start junk (still need to trim end): s:[0-9]+:"[ ]*
Regex for end junk: [";]+
3. Example Code
This would give us this PHP code:
$banText = file_get_contents("ban.txt");
/* Evil, evil regexes */
$sSegmentsRegex = '/s:[0-9]+:"[ ]*[0-9]+.[0-9]+.[0-9]+.[0-9]+"/';
$removeStartJunkRegex = '/s:[0-9]+:"[ ]*/';
$removeEndJunkRegex = '/[";]+/'; /* Could use rtrim on each if wanted */
$matches = array();
/* Find all 's' bits */
preg_match_all($sSegmentsRegex, $banText, $matches);
$matches = $matches[0]; /* preg_match_all changes $matches to array of arrays */
/* Remove start junk of each 's' bit */
$matches = preg_replace($removeStartJunkRegex, "", $matches);
$matches = preg_replace($removeEndJunkRegex, "", $matches);
foreach($matches as $ip) {
if($_SERVER["REMOTE_ADDR"] == $ip) {
die("Your IP is banned!");
}
}
print_r($matches); /* Shows the list of IP bans, remove this in your app */
Example: http://codepad.viper-7.com/S9rTQe
Related
I'm currently building a Slack bot using Laravel, and one of the features is that it can receive an email address and send a message to it.
The issue is that email addresses (e.g bob#example.com) come through as <mailto:bob#example.com|bob#example.com> from Slack.
I currently have a function that retrieves the email from this:
public function getEmail($string)
{
$pattern = '/[a-z0-9_\-\+]+#[a-z0-9\-]+\.([a-z]{2,3})(?:\.[a-z]{2})?/i';
preg_match_all($pattern, $string, $matches);
$matches = array_filter($matches);
return $matches[0][0];
}
This seemed to be working fine with email addresses like bob#example.com, however it seems to fail when working with email addresses like bob.jones#example.com (which would come through as <mailto:bob.jones#example.com|bob.jones#example.com>.
In these cases, the function is returning jones#example.com as the email address.
I'm not great with regex, but is there something else I could use/change in my pattern, or a better way to fetch the email address from the string provided by Slack?
Could always take regex out of the equation if you know that's always the format it'll be in:
$testString = '<mailto:bob#example.com|bob#example.com>';
$testString = str_replace(['<mailto:', '>'], '', $testString);
$addresses = explode('|', $testString);
echo $addresses[0];
This method will do the job and you avoid to have regular expressions. and make sure the email being returned is a real email address by validating it with php functions.
function getEmailAddress($string)
{
$string = trim($string, '<>');
$args = explode('|', $string);
foreach ($args as $_ => $val) {
if(filter_var($val, FILTER_VALIDATE_EMAIL) !== false) {
return $val;
}
}
return null;
}
echo getEmailAddress('<mailto:bob#example.com|bob#example.com>');
Output
bob#example.com
You know the strings containing the e-mail address will always be of the form <mailto:bob#example.com|bob#example.com>, so use that. Specifically, you know the string will start with <mailto:, will contain a |, and will end with >.
An added difficulty though, is that the local part of an e-mail address may contain a pipe character as well, but the domain may not; see the following question.
What characters are allowed in an email address?
public function getEmail($string)
{
$pattern = '/^<mailto:([^#]+#[^|]+)|(.*)>$/i';
preg_match_all($pattern, $string, $matches);
$matches = array_filter($matches);
return $matches[1][0];
}
This matches the full line from beginning to end, but we capture the e-mail address within the first set of parentheses. $matches[1] contains all matches from the first capturing parentheses. You could use preg_match instead, since you're not looking for all matches, just the first one.
I have a server application which looks up where the stress is in Russian words. The end user writes a word жажда. The server downloads a page from another server which contains the stresses indicated with apostrophes for each case/declension like this жа'жда. I need to find that word in the downloaded page.
In Russian the stress is always written after a vowel. I've been using so far a regex that is a grouping of all possible combinations (жа'жда|жажда'). Is there a more elegant solution using just a regex pattern instead of making a PHP script which creates all these combinations?
EDIT:
I have a word жажда
The downloaded page contains the string жа'жда. (notice the
apostrophe, I do not before-hand know where the apostrophe in the
word is)
I want to match the word with apostrophe (жа'жда).
P.S.: So far I have a PHP script creating the string (жа'жда|жажда') used in regex (apostrophe is only after vowels) which matches it. My goal is to get rid of this script and use just regex in case it's possible.
If I understand your question,
have these options (d'isorder|di'sorder|dis'order|diso'rder|disor'der|disord'er|disorde'r|disorder') and one of these is in the downloaded page and I need to find out which one it is
this may suit your needs:
<pre>
<?php
$s = "d'isorder|di'sorder|dis'order|diso'rder|disor'der|disord'er|disorde'r|disorder'|disorde'";
$s = explode("|",$s);
print_r($s);
$matches = preg_grep("#[aeiou]'#", $s);
print_r($matches);
running example: https://eval.in/207282
Uhm... Is this ok with you?
<?php
function find_stresses($word, $haystack) {
$pattern = preg_replace('/[aeiou]/', '\0\'?', $word);
$pattern = "/\b$pattern\b/";
// word = 'disorder', pattern = "diso'?rde'?r"
preg_match_all($pattern, $haystack, $matches);
return $matches[0];
}
$hay = "something diso'rder somethingelse";
find_stresses('disorder', $hay);
// => array(diso'rder)
You didn't specify if there can be more than one match, but if not, you could use preg_match instead of preg_match_all (faster). For example, in Italian language we have àncora and ancòra :P
Obviously if you use preg_match, the result would be a string instead of an array.
Based, on your code, and the requirements that no function is called and disorder is excluded. I think this is what you want. I have added a test vector.
<pre>
<?php
// test code
$downloadedPage = "
there is some disorde'r
there is some disord'er in the example
there is some di'sorder in the example
there also' is some order in the example
there is some disorder in the example
there is some dso'rder in the example
";
$word = 'disorder';
preg_match_all("#".preg_replace("#[aeiou]#", "$0'?", $word)."#iu"
, $downloadedPage
, $result
);
print_r($result);
$result = preg_grep("#'#"
, $result[0]
);
print_r($result);
// the code you need
$word = 'also';
preg_match("#".preg_replace("#[aeiou]#", "$0'?", $word)."#iu"
, $downloadedPage
, $result
);
print_r($result);
$result = preg_grep("#'#"
, $result
);
print_r($result);
Working demo: https://eval.in/207312
I thought I had this working; however after further evaluation it seems it's not working as I would have hoped it was.
I have a query pulling back a string. The string is a comma separated list just as you see here:
(1,145,154,155,158,304)
Nothing has been added or removed.
I have a function that I thought I could use preg_match to determine if the user's id was contained within the string. However, it appears that my code is looking for any part.
preg_match('/'.$_SESSION['MyUserID'].'/',$datafs['OptFilter_1']))
using the same it would look like such
preg_match('/1/',(1,145,154,155,158,304)) I would think. After testing if my user id is 4 the current code returns true and it shouldn't. What am I doing wrong? As you can see the id length can change.
It's better to have all your IDs in an array then checking if a desired ID is existed:
<?php
$str = "(1,145,154,155,158,304)";
$str = str_replace(array("(", ")"), "", $str);
$arr = explode(',', $str);
if(in_array($_SESSION['MyUserID'], $arr))
{
// ID existed
}
As your string - In dealing with Regular Expressions, however it's not recommended here, below regex will match your ID if it's there:
preg_match("#[,(]$ID[,)]#", $str)
Explanations:
[,(] # a comma , or opening-parenthesis ( character
$ID # your ID
[,)] # a comma , or closing-parenthesis ) character
Im trying to make the below function only return 1 email per domain.
Example: if i feed the function:
email1#domain.com email2#domain.com email1#domain.com
email1#domain.com email3#test.co.uk
I want it to return
email1#domain.com email3#test.co.uk
Here is the current function:
function remove_duplicates($str) {
# match all email addresses using a regular expression and store them
# in an array called $results
preg_match_all("([\w-]+(?:\.[\w-]+)*#(?:[\w-]+\.)+[a-zA-Z]{2,7})",$str,$results);
# sort the results alphabetically
sort($results[0]);
# remove duplicate results by comparing it to the previous value
$prev="";
while(list($key,$val)=each($results[0])) {
if($val==$prev) unset($results[0][$key]);
else $prev=$val;
}
# process the array and return the remaining email addresses
$str = "";
foreach ($results[0] as $value) {
$str .= "<br />".$value;
}
return $str;
};
Any ideas how to achieve this?
Something along these lines:
$emails = array('email1#domain.com', 'email2#domain.com', 'email1#domain.com', 'email1#domain.com', 'email3#test.co.uk');
$grouped = array();
foreach ($emails as $email) {
preg_match('/(?<=#)[^#]+$/', $email, $match);
$grouped[$match[0]] = $email;
}
var_dump($grouped);
This keeps the last occurrence of a domain, it's not hard to modify to keep the first instead if you require it.
You could simply use the array_unique function to do the job for you:
$emails = explode(' ', $emailString);
$emails = array_unique($emails);
The concept prev is not reliable unless all equal hostnames are in one continuous sequence. It would work if you were sorting by hostname, with a sorting function provided, but it's a bit of overkill.
Build an array with the hostnames, drop entries for which there is already a hostname in the array.
I'd suggest the following trick/procedure:
Change from one string to array of addresses. You do this with preg_match_all, others might do it with explode, all seems valid. So you have this already.
Extract the domain from the address. You could do this again with an regular expression or some other thing, I'd say it's trivial.
Now check if the domain has been already used, and if not, pick that email address.
The last point can be easily done by using an array and the domain as key. You can then use isset to see if it is already in use.
Edit: As deceze opted for a similar answer (he overwrites the matches per domain), the following code-example is a little variation. As you have got string input, I considered to iterate over it step by step to spare the temporary array of addresses and to do the adress and domain parsing at once. To do that, you need to take care of the offsets, which is supported by preg_match. Something similar is actually possible with preg_match_all however, you would then have the array again.
This code will pick the first and ignore the other addresses per domain:
$str = 'email1#domain.com email2#domain.com email1#domain.com email1#domain.com email3#test.co.uk';
$addresses = array();
$pattern = '/[\w-]+(?:\.[\w-]+)*#((?:[\w-]+\.)+[a-zA-Z]{2,7})/';
$offset = 0;
while (preg_match($pattern, $str, $matches, PREG_OFFSET_CAPTURE, $offset)) {
list(list($address, $pos), list($domain)) = $matches;
isset($addresses[$domain]) || $addresses[$domain] = $address;
$offset = $pos + strlen($address);
}
I have a string that contain links. I want my php to do different things with my links, depending on the url.
Answer:
function fixLinks($text)
{
$links = array();
$text = strip_tags($text);
$pattern = '!(https?://[^\s]+)!';
if (preg_match_all($pattern, $text, $matches)) {
list(, $links) = ($matches);
}
$i = 0;
$links2 = array();
foreach($links AS $link) {
if(strpos($link,'youtube.com') !== false) {
$search = "!(http://.*youtube\.com.*v=)?([a-zA-Z0-9_-]{11})(&.*)?!";
$youtube = 'http://www.youtube.com/watch?v=\\2';
$link2 = preg_replace($search, $youtube, $link);
} else {
$link2 = preg_replace('#(https?://([-\w\.]+)+(:\d+)?(/([\-\w/_\.]*(\?\S+)?)?)?)#', '<u>$1</u>', $link);
}
$links2[$i] = $link2;
$i++;
}
$text = str_replace($links, $links2, $text);
$text = nl2br($text);
return $text;
}
First of all, ditch eregi. It's deprecated and will disappear soon.
Then, doing this in just one pass is maybe a stretch too far. I think you'll be better off splitting this into three phases.
Phase 1 runs a regex search over your input, finding everything that looks like a link, and storing it in a list.
Phase 2 iterates over the list, checking whether a link goes to youtube (parse_url is tremendously useful for this), and putting a suitable replacement into a second list.
Phase 3: you now have two lists, one containing the original matches, one containing the desired replacements. Run str_replace over your original text, providing the match list for the search parameter and the replacement list for the replacements.
There are several advantages to this approach:
The regular expression for extracting links can be kept relatively simple, since it doesn't have to take special hostnames into account
It is easier to debug; you can dump the search and replace arrays prior to phase 3, and see if they contain what you expect
Because you perform all replacements in one go, you avoid problems with overlapping matches or replacing a piece of already-replaced text (after all, the replaced text still contains a URL, and you don't want to replace that again)
tdammers' answer is good, but another option is to use preg_replace_callback. If you go with that, then the process changes a little:
Create a regular expression to match all links, same as his Phase 1
In the callback, search for the YouTube video id. This will require running a second preg_match, which is (in my opinion) the biggest problem with this technique.
Return the replacement string, based on whether or not it's YouTube.
The code would look something like this:
function replaceem($matches) {
$url = $matches[0];
preg_match('~youtube\.com.*v=([\w\-]{11})~', $url, $matches);
return isset($matches[0]) ?
'<a href="youtube.php?id='.$matches[1].'" class="fancy">'.
'http://www.youtube.com/watch?v='.$matches[1].'</a>' :
'<a href="'.$url.'" title="Åben link" alt="Åben link" '.
'target="_blank">'.$url.'</a>';
}
$text = preg_replace_callback('~(?:f|ht)tps?://[^\s]+~', 'replaceem', $text);