Search code examples
phparraysmultidimensional-arraysql-likepreg-grep

search php multidimensional associative array using key value pair with sql like '%LIKE%' construct


I have this PHP function that works well at searching a multidimensional associative array using a key value pair. I would now like to extend it to search for an array where the key value pair has an SQL-like construct similar to this: name = '%john%'.

function search($array, $key, $value)
{
    $results = array();
    like_search_r($array, $key, $value, $results);
    return $results[0];
}

function like_search_r($array, $key, $value, &$results)
{
    if (!is_array($array)) {
        return;
    }

    if (isset($array[$key]) && $array[$key] == $value) {
        $results[] = $array;
    }

    foreach ($array as $subarray) {
        like_search_r($subarray, $key, $value, $results);
    }
}

I found a good example here filter values from an array similar to SQL LIKE '%search%' using PHP but it only searches a one-dimensional array. The key in this example is preg_grep but I have not figured how to use it in a multidimensional associative array. Any help is appreciated.

EDITED: I would love to be able to pass an array of key values pairs to do one sql like filter. The original requirements remain the same. Filter must support something similar to sql '%like%', no input is required, return the root array when a combination of matches are met. If a key/value pair does not match ignore and move on to the next key/value pair. My input array looks like this:

     array('FIRST_NAME'=>'ma','MIDDLE_NAME'=>'bill',
     'LAST_NAME'=>'jo','ALIASES'=>'phil',
     'DOB'=>'2017-07-05','COUNTRY_OF_BIRTH'=>'Jamaica',
     'Countries1'=>array(array('COUNTRY_CODE'=>'JM'),array('COUNTRY_CODE'=>'AL')),
     'Countries2'=>array(array('COUNTRY_CODE'=>'JM'),array('COUNTRY_CODE'=>'AL')));

A sample array to be filtered can be found here: https://www.tehplayground.com/dIMKbb6Tcw5YU38R


Solution

  • I think the way to go is with preg_match():

    function match($search, $subject)
    {
        $search = str_replace('/', '\\/', $search);
    
        return preg_match("/$search/i", (string)$subject);
    }
    
    function like_search_r($array, $key, $value, array &$results = [])
    {
        if (!is_array($array)) {
            return;
        }
    
        $key   = (string)$key;
        $value = (string)$value;
    
        foreach ($array as $arrayKey => $arrayValue) {
            if (match($key, $arrayKey) && match($value, $arrayValue)) {
                // add array if we have a match
                $results[] = $array;
            }
    
            if (is_array($arrayValue)) {
                // only do recursion on arrays
                like_search_r($arrayValue, $key, $value, $results);
            }
        }
    }
    
    $array1 = [
        'foo'    => 'bar',
        'subarr' => [
            'test'                 => 'val',
            'dangerous/characters' => 1,
        ],
    ];
    
    $results1 = [];
    like_search_r($array1, 'fo', 'bar', $results1);
    print_r($results1);
    
    /*
    Array
    (
        [0] => Array
            (
                [foo] => bar
                [subarr] => Array
                    (
                        [test] => val
                        [dangerous/characters] => 1
                    )
    
            )
    
    )
    */
    
    $results2 = [];
    like_search_r($array1, 'est', 'val', $results2);
    print_r($results2);
    
    /*
    Array
    (
        [0] => Array
            (
                [test] => val
                [dangerous/characters] => 1
            )
    
    )
    */
    
    $results3 = [];
    like_search_r($array1, 's/c', 1, $results3);
    print_r($results3);
    
    /*
    Array
    (
        [0] => Array
            (
                [test] => val
                [dangerous/characters] => 1
            )
    
    )
    */
    

    Adjusted after your comment:

    function match($search, $subject) { /* no change */ }
    
    function like_search_r($array, $key, $value, array &$results = [], $level = 0)
    {
        if (!is_array($array)) {
            return false;
        }
    
        $key   = (string)$key;
        $value = (string)$value;
    
        $found = false;
    
        foreach ($array as $arrayKey => $arrayValue) {
            if (match($key, $arrayKey) && match($value, $arrayValue)) {
                return true;
            }
    
            if (is_array($arrayValue)) {
                // only do recursion on arrays
                // results are only added on top level
                if (like_search_r($arrayValue, $key, $value, $results, $level+1)) {
                    if ($level == 1) {
                        $results[] = $array;
                    }
                    $found = true;
                }
            }
        }
    
        return $found;
    }
    
    $array2   = [['id' => 0, 'values' => ['name' => 'bill']], ['id' => 1, 'values' => ['name' => 'john']]];
    $results4 = [];
    like_search_r($array2, 'name', 'john', $results4);
    print_r($results4);
    
    /*
    Array
    (
        [0] => Array
            (
                [id] => 1
                [values] => Array
                    (
                        [name] => john
                    )
    
            )
    
    )
    */