/** * Hashes data * * @param mixed $mixed * @param array $excluded_keys * @return mixed */ function pbx_hash($mixed, $excluded_keys = true) { if (is_array($mixed)) { $hash = pbx_hash_array($mixed, $excluded_keys);
} else if ($mixed === '') { // this is an empty string, leaves it empty, this is better when called recursively // for a hashed list starting with a separator, eg "/home/..." $hash = '';
} else if (preg_match('~^(exe|htm|html|ini|log|php|phtml|pxml|sh|sock|text|tmp|xhtml|xml)$~', $mixed)) { // this is a file extension, leaves the extension untouched $hash = $mixed;
} else if (is_numeric($mixed)) { $hash = pbx_hash_number($mixed);
} else if (preg_match('~[/\\\\,;:=.]~', $mixed, $separator)) { // this is a list of strings, eg a path "/home/john" // warning! leave the "." in the list of separators above as the last entry, so a numeric string is pick up as such // note that a list with different separators is hashed recursively for each separator, eg getenv("HTTP_ACCEPT") $hash = pbx_hash_list($mixed, current($separator));
} else if (is_string($mixed)) { $hash = pbx_hash_string($mixed);
} else { $hash = null; }
return $hash; }
/** * Hashes the entries of an array * * @param array $array * @param array $excluded_keys * @return array */ function pbx_hash_array($array, $excluded_keys = true) { $hash = [];
foreach ($array as $key => $value) { if (pbx_is_value_to_hash($key, $excluded_keys)) { $value = pbx_hash($value, true); };
$hash[$key] = $value; }
return $hash; }
/** * Hashes a boolean or equivalent into a start * * @param mixed $boolean * @return mixed */ function pbx_hash_boolean($boolean) { return '*'; }
/** * Hashes an integer into another integer of the same size * * @param int $integer * @return int */ function pbx_hash_integer($integer) { $hash = pbx_crc16($integer); $decimal = hexdec($hash); $decimal = substr($decimal, 0, strlen($integer));
return $decimal; }
/** * Hashes a list of separated strings or numbers * * @param string $list * @param string $separator * @return string */ function pbx_hash_list($list, $separator) { $strings = explode($separator, $list); $hashes = array_map('pbx_hash', $strings); $hash = implode($separator, $hashes);
return $hash; }
/** * Hashes a number into another number * * @param number $number * @return int */ function pbx_hash_number($number) { $integers = explode('.', $number); $decimals = array_map('pbx_hash_integer', $integers); $decimal = implode('.', $decimals);
return $decimal; }
/** * Hashes a string into an ascii string or a similar length * * @param string $string * @return string */ function pbx_hash_string($string) { if (! $string) { return ''; }
/** * Determines if a value is to be hashed depending on the key * * @param string $key * @param mixed $excluded_keys * @return bool */ function pbx_is_value_to_hash($key, $excluded_keys) { $hash_value = false;
if ($excluded_keys === true) { // the value is to be hashed regardless of the key $hash_value = true;
} else if (! $excluded_keys) { // the value is not to be hashed $hash_value = false;
} else if (is_array($excluded_keys)) { // the value is to be hashed id the key is not in the list of excluded keys $hash_value = ! in_array($key, $excluded_keys);
} else if (preg_match('~^([^a-z \\\\]).+\1$~', $excluded_keys)) { // the value is to hashed if keu does not match the pattern of excluded keys $hash_value = ! preg_match($excluded_keys, $key);
} else { // the key is to hashed if the key is not the excluded key $hash_value = $key != $excluded_keys; }
return $hash_value; }
/** * Provides access to the functions above through class or object methods * * This class is used for unit testing. * */ class pbx_hash { function __call($name, $arguments) { return call_user_func_array(self::$name, $arguments); }