104

I am trying to detect whether a string contains at least one URL that is stored in an array.

Here is my array:

$owned_urls = array('website1.com', 'website2.com', 'website3.com');

The string is entered by the user and submitted via PHP. On the confirmation page I would like to check if the URL entered is in the array.

I have tried the following:

$string = 'my domain name is website3.com';
if (in_array($string, $owned_urls))
{
    echo "Match found"; 
    return true;
}
else
{
    echo "Match not found";
    return false;
}

No matter what is inputted the return is always "Match not found".

Is this the correct way of doing things?

0

15 Answers 15

118

Try this.

$string = 'my domain name is website3.com';
foreach ($owned_urls as $url) {
    //if (strstr($string, $url)) { // mine version
    if (strpos($string, $url) !== FALSE) { // Yoshi version
        echo "Match found"; 
        return true;
    }
}
echo "Not found!";
return false;

Use stristr() or stripos() if you want to check case-insensitive.

Sign up to request clarification or add additional context in comments.

3 Comments

from the manual: **Note**: If you only want to determine if a particular needle occurs within haystack, use the faster and less memory intensive function strpos() instead.
@danyo this won't work if the user enters a domain like site3.com. It will match mysite3.com when it shouldn't
it will be fine for it's intended use, as the urls will be limited to 2 or 3 preset ones
40

If you need it the other way round, i.e. to find if any of array elements contain a specific string, you can do it like this

$array = ["they has mystring in it", "some", "other", "elements"];
if (stripos(json_encode($array),'mystring') !== false) {
    echo "found mystring";
}

Though there is a chance for incorrect results:

  • a false negative result if your array elements contain characters that json_encode() will escape (e.g if mystring is http://google.com/)
  • a false positive result, e.g if mystring is "some","other". This code will tell you "found" while none of array elements contain such a string.

Hence explicit loop will be more bulletproof (or a brand new PHP function array_find()).

8 Comments

Your input array is actually a string.
I think this is the BEST ANSWER but didn't receive upvotes because of the simple mistake in the code. @Burgi I edited the answer and now it is array and even more, multiple sub arrays and his method still works very well!!
If you are going to convert the array to a string before checking, why not just implode? A good reason NOT to use json_encode() is if your array has characters in it that json_encode() will escape or mutate. This mutation risk is enough reason not to suggest this technique as a general use tool. Demonstration of failure: 3v4l.org/RjPbX
@AutoBaker and @mickmackusa I've tested this myself, and implode does not work. I don't know what your edit was, but it may have been rolled back, anyhow simply replacing json_encode($array) with implode(" ", $array) is not sufficient enough to make it work, at least from my tests. Using json_encode is still by far the best answer.
@Studocwho obviously it works (provided you need an answer to a different question than asked here).
|
26

Try this:

$owned_urls= array('website1.com', 'website2.com', 'website3.com');

$string = 'my domain name is website3.com';

$url_string = end(explode(' ', $string));

if (in_array($url_string,$owned_urls)){
    echo "Match found"; 
    return true;
} else {
    echo "Match not found";
    return false;
}

- Thanks

4 Comments

This assumes that the strings are separated by space. e.g. it won't work for the following string My url is https://website3.com
and even wont't work for 'I have the website3.com domain'. This assumes the string is in the end, which you can't when working with user-committed text
I agree with the other two commenters about why too much is assumed of the input data. This is not a great answer for researchers to rely upon because it is narrow in its functionality. Plus, the answer is missing its educational explanation. "Try this" answers miss an opportunity to educate/empower thousands of researchers.
end function wants an array reference as it's input parameter, it would be better to assign the result of explode(' ', $string) to a variable, and then feed it into end($yourArray). Cheers
26

Simple str_replace() with count parameter would work here:

$count = 0;
str_replace($owned_urls, '', $string, $count);
// if replace is successful means the array value is present(Match Found).
if ($count > 0) {
  echo "One of Array value is present in the string.";
}

3 Comments

Nice , I have one doubt .. this works fine for matching the url of string ... I have a string $string = 'you-are-nice'; $string2 = 'you-are-nicer'; and my $match = 'nice'; I need to match the word nice , not nicer even if my match string is nice ...
@Srinivas08 considering word boundaries is a reasonable consideration, but not one that can be implemented with str_replace().
The most prominent reason that devs should not implement this concise technique is because there is no way to "return early". In other words, after a replacement is made, there is absolutely no reason to continue searching for replacements, so the process should stop -- but it cannot. For all tasks where a binary "found" or "not found" result is sought, this technique should not be used as it will do useless additional iterating.
10

I think that a faster way is to use preg_match.

$user_input = 'Something website2.com or other';
$owned_urls_array = array('website1.com', 'website2.com', 'website3.com');

if ( preg_match('('.implode('|',$owned_urls_array).')', $user_input)){
    echo "Match found"; 
}else{
    echo "Match not found";
}

5 Comments

Thank you for this code snippet, which might provide some limited, immediate help. A proper explanation would greatly improve its long-term value by showing why this is a good solution to the problem and would make it more useful to future readers with other, similar questions. Please edit your answer to add some explanation, including the assumptions you’ve made. ref
To be more secure, dots must be escaped in pattern : addcslashes(implode('|', $owned_urls_array, '.'))
less code, but definitely much MUCH slower than strpos
Regex will be slower than strpos() in a head-to-head battle. I think the only reason to use preg_ for this type of task is if you wanted to include wordboundaries for increased accuracy. Do not use addcslashes() to escape special characters in regex, preg_quote() is specifically designed to take care of this necessity.
Also, the capture group is useless in the pattern.
8
$string = 'my domain name is website3.com';
$a = array('website1.com','website2.com','website3.com');

$result = count(array_filter($a, create_function('$e','return strstr("'.$string.'", $e);')))>0; 
var_dump($result );

output

bool(true)

2 Comments

for reference; create_function is deprecated in PHP 7.2
This answer is missing its educational explanation. The php manual states that strstr() should not be used to check for the existence of a string inside of a string -- it recommends strpos() for efficiency reasons. The count( and )>0 can be removed and (bool) added before array_filter() to convert the empty/non-empty array to false/true respectively.
6

Here is a mini-function that search all values from an array in a given string. I use this in my site to check for visitor IP is in my permitted list on certain pages.

function array_in_string($str, array $arr) {
    foreach($arr as $arr_value) { //start looping the array
        if (stripos($str,$arr_value) !== false) return true; //if $arr_value is found in $str return true
    }
    return false; //else return false
}

how to use

$owned_urls = array('website1.com', 'website2.com', 'website3.com');

//this example should return FOUND
$string = 'my domain name is website3.com';
if (array_in_string($string, $owned_urls)) {
    echo "first: Match found<br>"; 
}
else {
    echo "first: Match not found<br>";
}

//this example should return NOT FOUND
$string = 'my domain name is website4.com';
if (array_in_string($string, $owned_urls)) {
    echo "second: Match found<br>"; 
}
else {
    echo "second: Match not found<br>";
}

1 Comment

it IS case-sensitive, for a case-insensitive version use stripos
5

You can concatenate the array values with implode and a separator of | and then use preg_match to search for the value.

Here is the solution I came up with ...

$emails = array('@gmail', '@hotmail', '@outlook', '@live', '@msn', '@yahoo', '@ymail', '@aol');
$emails = implode('|', $emails);

if(!preg_match("/$emails/i", $email)){
 // do something
}

1 Comment

preg_match() is needless overhead for the search after imploding. There is no reason to not use stripos() with the same effect. I do not endorse this technique -- it is working harder than it needs to and is at risk of breaking if the $emails strings contain characters with special meaning to the regex engine.
3

If your $string is always consistent (ie. the domain name is always at the end of the string), you can use explode() with end(), and then use in_array() to check for a match (as pointed out by @Anand Solanki in their answer).

If not, you'd be better off using a regular expression to extract the domain from the string, and then use in_array() to check for a match.

$string = 'There is a url mysite3.com in this string';
preg_match('/(?:http:\/\/)?(?:www.)?([a-z0-9-_]+\.[a-z0-9.]{2,5})/i', $string, $matches);

if (empty($matches[1])) {
  // no domain name was found in $string
} else {
  if (in_array($matches[1], $owned_urls)) {
    // exact match found
  } else {
    // exact match not found
  }
}

The expression above could probably be improved (I'm not particularly knowledgeable in this area)

Here's a demo

1 Comment

Literal dots must be escaped in a regex pattern (unless in a character class). \w = [A-Za-z0-9_]. The preg_match() call itself can be placed inside of the first if to avoid making the empty() function call.
2

You are checking whole string to the array values. So output is always false.

I use both array_filter and strpos in this case.

<?php
$urls= array('website1.com', 'website2.com', 'website3.com');
$string = 'my domain name is website3.com';
$check = array_filter($urls, function($url){
    global $string;
    if(strpos($string, $url))
        return true;
});
echo $check?"found":"not found";

1 Comment

global can be replaced by using use().
1
$owned_urls= array('website1.com', 'website2.com', 'website3.com');
    $string = 'my domain name is website3.com';
    for($i=0; $i < count($owned_urls); $i++)
    {
        if(strpos($string,$owned_urls[$i]) != false)
            echo 'Found';
    }   

1 Comment

This answer is missing its educational explanation (or compelling statement why a researcher should use this technique over other techniques). The loop does not need to check count($owned_urls) on every iteration since the count never changes. The loop should break as soon as the first match is found.
1

I came up with this function which works for me, hope this will help somebody

$word_list = 'word1, word2, word3, word4';
$str = 'This string contains word1 in it';

function checkStringAgainstList($str, $word_list)
{
  $word_list = explode(', ', $word_list);
  $str = explode(' ', $str);

  foreach ($str as $word):
    if (in_array(strtolower($word), $word_list)) {
        return TRUE;
    }
  endforeach;

  return false;
}

Also, note that answers with strpos() will return true if the matching word is a part of other word. For example if word list contains 'st' and if your string contains 'street', strpos() will return true

1 Comment

This is very inefficient. The OP does not ask for two strings to be exploded on spaces. This answer is unnecessarily complex, risks breaking up a string that should not return a match but then returns a match because unordered individual substrings all qualify. I do not recommend this approach since it is prone to failures.
0
    $message = "This is test message that contain filter world test3";

    $filterWords = array('test1', 'test2', 'test3');

    $messageAfterFilter =  str_replace($filterWords, '',$message);

    if( strlen($messageAfterFilter) != strlen($message) )
        echo 'message is filtered';
    else
        echo 'not filtered';

1 Comment

If bothering to "check by mutation" (I wouldn't), then just use this earlier posted and simpler answer: stackoverflow.com/a/40543118/2943403 (both answers suffer from inefficiency as neither have any way of halting when a match is found)
0

I find this fast and simple without running loop.

$array = array("this", "that", "there", "here", "where");
$string = "Here comes my string";
$string2 = "I like to Move it! Move it";

$newStr = str_replace($array, "", $string);

if(strcmp($string, $newStr) == 0) {
    echo 'No Word Exists - Nothing got replaced in $newStr';
} else {
    echo 'Word Exists - Some Word from array got replaced!';
}

$newStr = str_replace($array, "", $string2);

if(strcmp($string2, $newStr) == 0) {
    echo 'No Word Exists - Nothing got replaced in $newStr';
} else {
    echo 'Word Exists - Some Word from array got replaced!';
}

Little explanation!

  1. Create new variable with $newStr replacing value in array of original string.

  2. Do string comparison - If value is 0, that means, strings are equal and nothing was replaced, hence no value in array exists in string.

  3. if it is vice versa of 2, i.e, while doing string comparison, both original and new string was not matched, that means, something got replaced, hence value in array exists in string.

1 Comment

If bothering to "check by mutation" (I wouldn't), then just use this earlier posted and simpler answer: stackoverflow.com/a/40543118/2943403 (both answers suffer from inefficiency as neither have any way of halting when a match is found)
0
  $search = "web"
    $owned_urls = array('website1.com', 'website2.com', 'website3.com');
          foreach ($owned_urls as $key => $value) {
         if (stristr($value, $search) == '') {
        //not fount
        }else{
      //found
       }

this is the best approach search for any substring , case-insensitive and fast

just like like im mysql

ex:

select * from table where name = "%web%"

1 Comment

The php manual states that strstr() (or stristr() in this context) should not be used to determine the existence of a string in another string. For this purpose, the php manual recommends strpos()/stripos() for efficiency reasons.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.