You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
353 lines
8.7 KiB
353 lines
8.7 KiB
1 year ago
|
<?php
|
||
|
/*
|
||
|
** Zabbix
|
||
|
** Copyright (C) 2001-2023 Zabbix SIA
|
||
|
**
|
||
|
** This program is free software; you can redistribute it and/or modify
|
||
|
** it under the terms of the GNU General Public License as published by
|
||
|
** the Free Software Foundation; either version 2 of the License, or
|
||
|
** (at your option) any later version.
|
||
|
**
|
||
|
** This program is distributed in the hope that it will be useful,
|
||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
** GNU General Public License for more details.
|
||
|
**
|
||
|
** You should have received a copy of the GNU General Public License
|
||
|
** along with this program; if not, write to the Free Software
|
||
|
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||
|
**/
|
||
|
|
||
|
|
||
|
class CArrayHelper {
|
||
|
|
||
|
/**
|
||
|
* @var array
|
||
|
*/
|
||
|
protected static $fields;
|
||
|
|
||
|
private function __construct() {}
|
||
|
|
||
|
/**
|
||
|
* Copies keys according to given map for given array of the objects.
|
||
|
*
|
||
|
* @param array $array
|
||
|
* @param array $field_map
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
public static function copyObjectsKeys(array $array, array $field_map) {
|
||
|
foreach ($array as &$object) {
|
||
|
foreach ($field_map as $old_key => $new_key) {
|
||
|
$object[$new_key] = $object[$old_key];
|
||
|
}
|
||
|
}
|
||
|
unset($object);
|
||
|
|
||
|
return $array;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get from array only values with given keys.
|
||
|
* If requested key is not in given array exception is thrown.
|
||
|
*
|
||
|
* @static
|
||
|
* @throws InvalidArgumentException
|
||
|
*
|
||
|
* @param array $array
|
||
|
* @param array $keys
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
public static function getByKeysStrict(array $array, array $keys) {
|
||
|
$result = [];
|
||
|
foreach ($keys as $key) {
|
||
|
if (!isset($array[$key])) {
|
||
|
throw new InvalidArgumentException(sprintf('Array does not have element with key "%1$s".', $key));
|
||
|
}
|
||
|
$result[$key] = $array[$key];
|
||
|
}
|
||
|
|
||
|
return $result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get values with the $keys from $array.
|
||
|
* If the requested key is not in the given array it is skipped.
|
||
|
*
|
||
|
* @static
|
||
|
*
|
||
|
* @param array $array
|
||
|
* @param array $keys
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
public static function getByKeys(array $array, array $keys) {
|
||
|
$result = [];
|
||
|
foreach ($keys as $key) {
|
||
|
if (array_key_exists($key, $array)) {
|
||
|
$result[$key] = $array[$key];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Select sub-array of array items with keys in given numeric range.
|
||
|
*
|
||
|
* @static
|
||
|
*
|
||
|
* @param array $array Array with numeric keys to test for given range.
|
||
|
* @param int $start Range start value.
|
||
|
* @param int $end Range end value.
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
public static function getByKeysRange(array $array, $start, $end) {
|
||
|
$result = [];
|
||
|
foreach ($array as $key => $val) {
|
||
|
if ($key >= $start && $key <= $end) {
|
||
|
$result[$key] = $val;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Renames array elements keys according to given map.
|
||
|
*
|
||
|
* @param array $array
|
||
|
* @param array $field_map
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
public static function renameKeys(array $array, array $field_map) {
|
||
|
foreach ($field_map as $old_key => $new_key) {
|
||
|
if (array_key_exists($old_key, $array)) {
|
||
|
$array[$new_key] = $array[$old_key];
|
||
|
unset($array[$old_key]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $array;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Renames keys according to given map for given array of the objects.
|
||
|
*
|
||
|
* @param array $array
|
||
|
* @param array $field_map
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
public static function renameObjectsKeys(array $array, array $field_map) {
|
||
|
foreach ($array as &$object) {
|
||
|
foreach ($field_map as $old_key => $new_key) {
|
||
|
$object[$new_key] = $object[$old_key];
|
||
|
unset($object[$old_key]);
|
||
|
}
|
||
|
}
|
||
|
unset($object);
|
||
|
|
||
|
return $array;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sort array by multiple fields.
|
||
|
*
|
||
|
* @static
|
||
|
*
|
||
|
* @param array $array array to sort passed by reference
|
||
|
* @param array $fields fields to sort, can be either string with field name or array with 'field' and 'order' keys
|
||
|
*/
|
||
|
public static function sort(array &$array, array $fields) {
|
||
|
foreach ($fields as $fid => $field) {
|
||
|
if (!is_array($field)) {
|
||
|
$fields[$fid] = ['field' => $field, 'order' => ZBX_SORT_UP];
|
||
|
}
|
||
|
}
|
||
|
self::$fields = $fields;
|
||
|
uasort($array, [self::class, 'compare']);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Method to be used as callback for uasort function in sort method.
|
||
|
*
|
||
|
* @TODO: with PHP 5.3+ this should be changed to closure
|
||
|
* @static
|
||
|
*
|
||
|
* @param $a
|
||
|
* @param $b
|
||
|
*
|
||
|
* @return int
|
||
|
*/
|
||
|
protected static function compare($a, $b) {
|
||
|
foreach (self::$fields as $field) {
|
||
|
// if field is not set or is null, treat it as smallest string
|
||
|
// strnatcasecmp() has unexpected behaviour with null values
|
||
|
if (!isset($a[$field['field']]) && !isset($b[$field['field']])) {
|
||
|
$cmp = 0;
|
||
|
}
|
||
|
elseif (!isset($a[$field['field']])) {
|
||
|
$cmp = -1;
|
||
|
}
|
||
|
elseif (!isset($b[$field['field']])) {
|
||
|
$cmp = 1;
|
||
|
}
|
||
|
else {
|
||
|
$cmp = strnatcasecmp($a[$field['field']], $b[$field['field']]);
|
||
|
}
|
||
|
|
||
|
if ($cmp != 0) {
|
||
|
return $cmp * ($field['order'] == ZBX_SORT_UP?1:-1);
|
||
|
}
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sort array by keys in ascending order.
|
||
|
* Performs case-insensitive string comparisons using a "natural order" algorithm.
|
||
|
*
|
||
|
* @param array $array
|
||
|
*/
|
||
|
public static function ksort(array &$array): void {
|
||
|
uksort($array, 'strnatcasecmp');
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Unset values that are contained in $a2 from $a1. Skip arrays and keys given in $skipKeys.
|
||
|
*
|
||
|
* @param array $a1 array to modify
|
||
|
* @param array $a2 array to compare with
|
||
|
* @param array $skipKeys fields to ignore
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
public static function unsetEqualValues(array $a1, array $a2, array $skipKeys = []) {
|
||
|
// ignore given fields
|
||
|
foreach ($skipKeys as $key) {
|
||
|
unset($a2[$key]);
|
||
|
}
|
||
|
|
||
|
foreach ($a1 as $key => $value) {
|
||
|
// check if the values under $key are equal, skip arrays
|
||
|
if (isset($a2[$key]) && !is_array($value) && !is_array($a2[$key])
|
||
|
&& (string) $a1[$key] === (string) $a2[$key]) {
|
||
|
unset($a1[$key]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $a1;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Checks if array $arrays contains arrays with duplicate values under the $uniqueField key. If a duplicate exists,
|
||
|
* returns the first duplicate, otherwise returns null.
|
||
|
*
|
||
|
* Example 1:
|
||
|
* $data = array(
|
||
|
* array('name' => 'CPU load'),
|
||
|
* array('name' => 'CPU load'),
|
||
|
* array('name' => 'Free memory')
|
||
|
* );
|
||
|
* var_dump(CArrayHelper::findDuplicate($data, 'name')); // returns array with index 1
|
||
|
*
|
||
|
* Example 2:
|
||
|
* $data = array(
|
||
|
* array('host' => 'Zabbix server', 'name' => 'CPU load'),
|
||
|
* array('host' => 'Zabbix server', 'name' => 'Free memory'),
|
||
|
* array('host' => 'Linux server', 'name' => 'CPU load'),
|
||
|
* array('host' => 'Zabbix server', 'name' => 'CPU load')
|
||
|
* );
|
||
|
* var_dump(CArrayHelper::findDuplicate($data, 'name', 'host')); // returns array with index 3
|
||
|
*
|
||
|
* @param array $arrays an array of arrays
|
||
|
* @param string $uniqueField key to be used as unique criteria
|
||
|
* @param string $uniqueField2 second key to be used as unique criteria
|
||
|
*
|
||
|
* @return null|array the first duplicate found or null if there are no duplicates
|
||
|
*/
|
||
|
public static function findDuplicate(array $arrays, $uniqueField, $uniqueField2 = null) {
|
||
|
$uniqueValues = [];
|
||
|
|
||
|
foreach ($arrays as $array) {
|
||
|
$value = $array[$uniqueField];
|
||
|
|
||
|
if ($uniqueField2 !== null) {
|
||
|
$uniqueByValue = $array[$uniqueField2];
|
||
|
|
||
|
if (isset($uniqueValues[$uniqueByValue]) && isset($uniqueValues[$uniqueByValue][$value])) {
|
||
|
return $array;
|
||
|
}
|
||
|
$uniqueValues[$uniqueByValue][$value] = $value;
|
||
|
}
|
||
|
else {
|
||
|
if (isset($uniqueValues[$value])) {
|
||
|
return $array;
|
||
|
}
|
||
|
$uniqueValues[$value] = $value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sort an array of objects so that the objects whose $field value matches $pattern are at the top. Return the first
|
||
|
* $limit objects.
|
||
|
*
|
||
|
* @param array $array Array of objects to sort.
|
||
|
* @param string $field Name of the field to search.
|
||
|
* @param string $pattern String to match the value against $field.
|
||
|
* @param int $limit Number of objects to return.
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
public static function sortByPattern(array $array, $field, $pattern, $limit) {
|
||
|
$chunk_size = $limit;
|
||
|
|
||
|
$result = [];
|
||
|
|
||
|
foreach ($array as $key => $value) {
|
||
|
if (mb_strtolower($value[$field]) === mb_strtolower($pattern)) {
|
||
|
$result = [$key => $value] + $result;
|
||
|
}
|
||
|
elseif ($limit > 0) {
|
||
|
$result[$key] = $value;
|
||
|
}
|
||
|
else {
|
||
|
continue;
|
||
|
}
|
||
|
$limit--;
|
||
|
}
|
||
|
|
||
|
if ($result) {
|
||
|
$result = array_chunk($result, $chunk_size, true);
|
||
|
$result = $result[0];
|
||
|
}
|
||
|
|
||
|
return $result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Check if given array is hash or just normal indexed array.
|
||
|
*
|
||
|
* @param array $value
|
||
|
*
|
||
|
* @return bool true if value is hash array, false otherwise
|
||
|
*/
|
||
|
public static function isHash($value): bool
|
||
|
{
|
||
|
$expectedKey = 0;
|
||
|
|
||
|
foreach ($value as $key => $val) {
|
||
|
if ($key !== $expectedKey++) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
}
|