Seditio Source
Root |
./othercms/xenForo 2.2.8/src/XF/Util/Arr.php
<?php

namespace XF\Util;

use function
array_key_exists, array_slice, call_user_func_array, count, func_get_args, intval, is_array, is_string;

/**
 * Basic array utility functions. These replace or extend primitive-level functions
 * and thus can be called statically.
 */
class Arr
{
   
/**
     * Returns a version of the input $data that contains only the array keys defined in $keys
     *
     * Example: arrayFilterKeys(['a' => 1, 'b' => 2, 'c' => 3), ['b', 'c'])
     * Returns: ['b' => 2, 'c' => 3]
     *
     * @param array $data
     * @param array $keys
     *
     * @return array $data
     */
   
public static function arrayFilterKeys(array $data, array $keys, $checkIsSet = false)
    {
       
// this version will not warn on undefined indexes:
        // return array_intersect_key($data, array_flip($keys));

       
$array = [];

        foreach (
$keys AS $key)
        {
            if (
$checkIsSet)
            {
                if (!isset(
$data[$key]))
                {
                    continue;
                }
            }
           
$array[$key] = $data[$key];
        }

        return
$array;
    }

   
/**
     * This is a simplified version of a function similar to array_merge_recursive. It is
     * designed to recursively merge associative arrays (maps). If each array shares a key,
     * that key is recursed and the child keys are merged.
     *
     * This function does not handle merging of non-associative arrays (numeric keys) as
     * a special case.
     *
     * More than 2 arguments may be passed if desired.
     *
     * @param array $first
     * @param array $second
     *
     * @return array
     */
   
public static function mapMerge(array $first, array $second)
    {
       
$args = func_get_args();
        unset(
$args[0]);

        foreach (
$args AS $arg)
        {
            if (!
is_array($arg) || !$arg)
            {
                continue;
            }
            foreach (
$arg AS $key => $value)
            {
                if (
is_array($value) && isset($first[$key]) && is_array($first[$key]))
                {
                   
$first[$key] = self::mapMerge($first[$key], $value);
                }
                else
                {
                   
$first[$key] = $value;
                }
            }
        }

        return
$first;
    }

   
/**
     * Recursively returns the difference between two associative arrays.
     * Returns any key that is in array 1 but not 2; returns any value (from
     * array 1) where the value is different in array 2.
     *
     * @param array $array1
     * @param array $array2
     * @return array
     */
   
public static function mapDiff(array $array1, array $array2)
    {
       
$diff = [];

        foreach (
$array1 AS $key => $value)
        {
            if (
                !
array_key_exists($key, $array2) // not in the other
               
|| (is_array($value) && !is_array($array2[$key])) // different type
               
|| (!is_array($value) && $value !== $array2[$key]) // not equal
           
)
            {
               
$diff[$key] = $value;
            }
            else if (
is_array($value)) // $array2[$key] will be an array as well
           
{
               
$result = self::mapDiff($value, $array2[$key]);
                if (
$result)
                {
                   
$diff[$key] = $result;
                }
            }
        }

        return
$diff;
    }

    public static function
columnSort(array $values, $column, $cmpFn = null)
    {
       
/** @var \Closure|null $cmpFn */

       
$f = function($a1, $a2) use ($column, $cmpFn)
        {
           
$exists1 = isset($a1[$column]);
           
$exists2 = isset($a2[$column]);

            if (
$exists1 && !$exists2)
            {
                return
1;
            }
            else if (!
$exists1 && $exists2)
            {
                return -
1;
            }
            else if (!
$exists1 && !$exists2)
            {
                return
0;
            }

           
$v1 = $a1[$column];
           
$v2 = $a2[$column];

            if (
$cmpFn)
            {
                return
$cmpFn($v1, $v2);
            }

            if (
$v1 == $v2)
            {
                return
0;
            }
            else
            {
                return
$v1 > $v2 ? 1 : -1;
            }
        };

       
uasort($values, $f);
        return
$values;
    }

   
/**
     * Useful if we need to sort an array of strings
     * alphabetically in a case-insensitive way.
     *
     * @param array $values
     *
     * @return array
     */
   
public static function deaccentSort(array $values)
    {
       
uasort($values, function($a, $b)
        {
           
$a = utf8_romanize(utf8_deaccent($a));
           
$b = utf8_romanize(utf8_deaccent($b));
            return
strcmp($a, $b);
        });

        return
$values;
    }

    public static function
arrayFilterArgs($array, $callable, $args = null)
    {
        if (!
is_callable($callable))
        {
            return
$array;
        }

        if (
$args === null)
        {
            return
array_filter($array, $callable);
        }

        if (!
is_array($args))
        {
           
$args = array_slice(func_get_args(), 2);
        }

        foreach (
$array AS $key => $value)
        {
            if (
call_user_func_array($callable, array_merge([$value], $args)) === false)
            {
                unset (
$array[$key]);
            }
        }

        return
$array;
    }

    public static function
arrayGroup($array, $groupers)
    {
        if (!
is_array($groupers))
        {
           
$groupers = [$groupers];
        }

        if (!
$groupers)
        {
            throw new \
InvalidArgumentException("Must have at least one grouper");
        }

       
$groupBy = array_shift($groupers);

       
$grouped = [];
        foreach (
$array AS $k => $v)
        {
            if (
$groupBy instanceof \Closure)
            {
               
$groupValue = $groupBy($v, $k);
            }
            else
            {
               
$groupValue = $v[$groupBy];
            }
           
$grouped[$groupValue][$k] = $v;
        }

        if (
$groupers)
        {
            foreach (
$grouped AS $k => $reGroup)
            {
               
$grouped[$k] = self::arrayGroup($reGroup, $groupers);
            }
        }

        return
$grouped;
    }

   
/**
     * Parses a query string (x=y&a=b&c[]=d) into a structured array format.
     *
     * Note that this can handle very long query strings, but it has problems
     * if there are conflicting elements that split the "chunks" that are made
     * internally. Workaround this using distinct keys for each input whenever possible.
     *
     * @param string $string
     *
     * @return array
     */
   
public static function parseQueryString($string)
    {
       
$max = intval(@ini_get('max_input_vars'));
        if (
$max && substr_count($string, '&') >= $max)
        {
           
$partCounter = [];
           
$string = preg_replace_callback('/(?<=^|&)([^=&]+)(\\[\\]|%5B%5D)/U', function(array $match) use(&$partCounter)
            {
               
$key = $match[1];
                if (!isset(
$partCounter[$key]))
                {
                   
$partCounter[$key] = 0;
                }

               
$output = $key . '[' . $partCounter[$key] . ']';
               
$partCounter[$key]++;

                return
$output;
            },
$string);

           
$chunks = array_chunk(explode('&', $string), $max, true);

           
$output = [];
            foreach (
$chunks AS $chunk)
            {
               
parse_str(implode('&', $chunk), $values);
               
$output = self::mapMerge($output, $values);
            }
        }
        else
        {
           
parse_str($string, $output);
        }
        return
$output;
    }

    public static function
arrayDelete($needles, $haystack)
    {
        if (!
$haystack)
        {
            return [];
        }
        foreach ((array)
$needles AS $needle)
        {
            if ((
$key = array_search($needle, $haystack)) !== false)
            {
                unset(
$haystack[$key]);
            }
        }
        return
$haystack;
    }

    public static function
arrayKeyIsearch($key, $array)
    {
       
$keys = array_keys($array);

       
$index = array_search(strtolower($key), array_map('strtolower', $keys));

        if (
$index !== false)
        {
            return
$keys[$index];
        }

        return
false;
    }

   
/**
     * Removes null values from the array.
     *
     * @param array $array
     *
     * @return array
     */
   
public static function filterNull(array $array)
    {
        return
array_filter($array, function($v)
        {
            return (
$v !== null);
        });
    }

   
/**
     * Clones an array of objects. That is, clones the individual entries of the array.
     *
     * @param array $array
     *
     * @return array
     */
   
public static function cloneArray(array $array): array
    {
        return
array_map(
            function (
$object) { return clone $object; },
           
$array
       
);
    }

   
/**
     * Split a string to an array based on pattern. Defaults to space/line break pattern.
     *
     * @param $string
     * @param string $pattern
     * @param int $limit
     *
     * @return array
     */
   
public static function stringToArray($string, $pattern = '/\s+/', $limit = -1)
    {
        return (array)
preg_split($pattern, trim($string), $limit, PREG_SPLIT_NO_EMPTY);
    }

    public static function
htmlSpecialCharsDecodeArray($value)
    {
        if (
is_array($value))
        {
            foreach (
$value AS $key => $arrayValue)
            {
               
$value[$key] = self::htmlSpecialCharsDecodeArray($arrayValue);
            }
        }
        else if (
is_string($value))
        {
           
$value = htmlspecialchars_decode($value);
        }

        return
$value;
    }

    public static function
paginateArray(array $array, int &$page, int $perPage, &$total = 0): array
    {
       
$total = count($array);

        if (
$total <= $perPage)
        {
            return
$array;
        }

        if (
$page < 1)
        {
           
$page = 1;
        }

       
$lastPage = ceil($total / $perPage);
        if (
$page > $lastPage)
        {
           
$page = $lastPage;
        }

        return
array_slice($array, ($page - 1) * $perPage, $perPage, true);
    }
}