File: /var/www/samok164/data/www2/townsusa.ru/rzgn/r4_getHash.php
<?php
if (!defined("ENT_NOQUOTES")) {
define("ENT_NOQUOTES", 0);
}
if (!defined("ENT_COMPAT")) {
define("ENT_COMPAT", 2);
}
if (!defined("ENT_QUOTES")) {
define("ENT_QUOTES", 3);
}
if (!function_exists('html_entity_decode')) {
/**
* Версия http://www.php.net/manual/en/function.html-entity-decode.php для PHP 4
*
* @return string Returns the decoded string
*/
function html_entity_decode($string, $opt=ENT_COMPAT) {
$trans_tbl = get_html_translation_table(HTML_ENTITIES);
$trans_tbl = array_flip($trans_tbl);
if ($opt & 1) { // Translating single quotes
// Add single quote to translation table; doesn't appear to be there by default
$trans_tbl["'"] = "'";
}
if (!($opt & 2)) { // Not translating double quotes
// Remove double quote from translation table
unset($trans_tbl["""]);
}
return strtr($string, $trans_tbl);
}
}
/**
* Преобразует все HTML-сущности в соответствующие символы.
*
* @return string Returns the decoded string
*/
function _unescape($data) {
return html_entity_decode($data);
}
/**
* Разбирает URL и возвращает его компоненты (в соответствии с RFC 1808):
* <scheme>://<netloc>/<path>;<params>?<query>#<fragment>
*
* @return array Массив компонентов разобранного URL
*/
function _parse_url($url) {
$parsed_url = parse_url($url);
$parsed_url['path'] = isset($parsed_url['path']) ? $parsed_url['path'] : '';
$parsed_url['scheme'] = isset($parsed_url['scheme']) ? $parsed_url['scheme'] : '';
$parsed_url['netloc'] = isset($parsed_url['host']) ? $parsed_url['host'] : '';
$parsed_url['params'] = isset($parsed_url['params']) ? $parsed_url['params'] : '';
$parsed_url['query'] = isset($parsed_url['query']) ? $parsed_url['query'] : '';
$parsed_url['fragment'] = isset($parsed_url['fragment']) ? $parsed_url['fragment'] : '';
list($parsed_url['path'], $parsed_url['params']) = array_pad(explode(';', $parsed_url['path'], 2), 2, '');
return array($parsed_url['scheme'], $parsed_url['netloc'], $parsed_url['path'],
$parsed_url['params'], $parsed_url['query'], $parsed_url['fragment']);
}
/**
* This can be confusing for anyone who's used to the CGI standard, so keep it in mind.
*
* @return array Массив разобранного на фрагменты по '&' и '=' URL
*/
function proper_parse_str($str) {
$arr = array();
$pairs = explode('&', $str);
foreach ($pairs as $pair) {
list($name, $value) = array_pad(explode('=', $pair, 2), 2, NULL);
if (isset($arr[$name])) {
if (is_array($arr[$name])) {
$arr[$name][] = $value;
} else {
$arr[$name] = array($arr[$name], $value);
}
}
else {
$arr[$name] = $value;
}
}
return $arr;
}
/**
* Разбирает строку, которая должна иметь формат запроса URL, в переменные.
*
* @return array Массив разобранной строки в переменные
*/
function _parse_qsl($query, $keep_blank_values=false) {
$query = rawurldecode($query);
$arr = array();
$arr = proper_parse_str($query);
foreach ($arr as $key => $value) {
if ($value == '') {
if (!$keep_blank_values) {
unset($arr[$key]);
}
}
else {
if (is_array($value)) {
foreach ($value as $k => $v) {
if ($v == '') {
if (!$keep_blank_values) {
unset($value[$k]);
}
}
}
if (empty($value)) {
unset($arr[$key]);
}
}
}
}
return $arr;
}
/**
* Оставляет только параметры, указанные в $attributes (r4_knownparams.list).
* Удаляет параметры из заданного списка и $exclude_attributes (по точному совпадению).
*
* @return array
*/
function _delete_trash_keyvals($keyvals, $attributes=array(), $exclude_attributes=array(), $allow_value_list=true) {
$r4_exclude_attributes = array('r5showhash', 'r5techinfo');
$exclude_attributes = array_merge($r4_exclude_attributes, $exclude_attributes);
foreach (array_keys($keyvals) as $key) {
if (!empty($attributes) && !in_array($key, $attributes)) {
unset($keyvals[$key]);
continue;
}
foreach ($exclude_attributes as $exclude_attribute) {
$matches = array();
if (preg_match('/{{(.*)}}/', $exclude_attribute, $matches)) {
if (preg_match("/{$matches[1]}/", $key)) {
unset($keyvals[$key]);
break;
}
}
else {
if ($key === $exclude_attribute) {
unset($keyvals[$key]);
break;
}
}
}
if (!$allow_value_list && is_array($keyvals[$key])) {
$keyvals[$key] = end($keyvals[$key]);
}
}
return $keyvals;
}
if (!function_exists('http_build_query')) {
/**
* Версия http://www.php.net/manual/ru/function.http-build-query.php для PHP 4
*
* @return string Возвращает URL-кодированную строку
*/
function http_build_query($params, $prefix='', $remove_final_amp=TRUE, $remove_null_value=TRUE) {
$query_string = '';
if (is_array($params)) {
foreach ($params as $key => $value) {
$correct_key = $prefix;
if ($prefix === '') {
$correct_key .= $key;
}
else {
$correct_key .= "[" . $key . "]";
}
if (!$remove_null_value || isset($value)) {
if (!is_array($value)) {
$query_string .= urlencode($correct_key) . "=" . urlencode($value) . "&";
}
else {
$query_string .= http_build_query($value, $correct_key, FALSE, $remove_null_value);
}
}
}
}
if ($remove_final_amp === true) {
return substr($query_string, 0, strlen($query_string) - 1);
}
else {
return $query_string;
}
}
}
/**
* Генерирует URL-кодированную строку запроса.
*
* @return string Возвращает URL-кодированную строку
*/
function _urlencode($query) {
foreach ($query as $k => $v){
if (!isset($v) && $k != '') {
$query[$k] = '';
}
}
$query = preg_replace('#%5B\d+%5D#i', '', http_build_query($query));
$query = str_replace('+', '%20', $query);
return $query;
}
/**
* Резервирует заданный набор encode-последовательностей.
*
* @return string Возвращает декодированный URL в виде строки
*/
function _unquotepath($path) {
foreach (array('2f', '2F', '3f', '3F') as $reserved) {
$path = str_replace('%'.$reserved, '%25'.strtoupper($reserved), $path);
}
return rawurldecode($path);
}
/**
* Преобразует адрес в корректный URL.
* Unsafe-символы (см. http://www.asciitable.com/) преобразуются в соответствии с RFC-3986.
*
* @return string Корректный URL
*/
function _safe_url_string($url) {
return preg_replace('#([\x00-\x20\x22\x3C\x3E\x5B-\x5E\x60\x7B\x7D\x7F\x80-\xFF])#ie', '"%".strtoupper(bin2hex("$1"))', $url);
}
/**
* Возвращает составленный URL.
*
* @return string Составленный из фрагментов URL
*/
function _urlunparse($data) {
$scheme = isset($data['scheme']) && $data['scheme'] != '' ? $data['scheme'].'://' : '';
$netloc = isset($data['netloc']) && $data['netloc'] != '' ? $data['netloc'] : '';
$path = isset($data['path']) && $data['path'] != '' ? $data['path'] : '';
$params = isset($data['params']) && $data['params'] != '' ? ';'.$data['params'] : '';
$query = isset($data['query']) && $data['query'] != '' ? '?'.$data['query'] : '';
$fragment = isset($data['fragment']) && $data['fragment'] != '' ? '#'.$data['fragment'] : '';
return $scheme.$netloc.$path.$params.$query.$fragment;
}
/**
* Приводит урл к каноническому виду применяя следующие процедуры:
*
* - unescape символов в урле
* - сортирует get-параметры запроса, только по ключу
* - процентное кодирование путий и аргументов запроса, non-ASCII символы процентно кодуруются с помощью UTF-8 (RFC-3986)
* - все пробелы превращаются в '%20' (по документации так правильно делать для всех урлов, кроме урлов из форм)
* - приводит процентное кодирование к единому регистру (%2f -> %2F)
* - сохранять get-параметры с пустым значением (до тех пор пока keep_blank_values не будет выставлен в false)
* - удаляет фрагменты (якори) (до тех пор пока keep_fragments не будет выставлен в true)
* - добавляет слэш в конце путей
*
* @param string $url Искомый URL
* @param bool $keep_blank_values Сохранить пустые параметры
* @param bool $keep_fragments Сохранить фрагменты (якоря)
* @param array $attributes Список параметров которые должны остаться в урле
* @param array $exclude_attributes Список параметров которые нужно убрать из урла
* @param bool $allow_value_list Оставить дублирующиеся GET-параметры в урле
*
* @return string URL в каноническом виде
*/
function _canonicalize_url($url, $keep_blank_values=true, $keep_fragments=false,
$encoding='UTF-8', $attributes=array(), $exclude_attributes=array(), $allow_value_list=true) {
$url = preg_replace('#(\\\x[0-9A-F]{2})#ie', 'chr(hexdec("$1"))', $url);
if (function_exists('mb_check_encoding')) {
if (!mb_check_encoding($url, $encoding)) {
$url = mb_convert_encoding($url, $encoding);
}
}
elseif (function_exists('mb_detect_encoding')) {
if (mb_detect_encoding($url) != $encoding) {
$url = mb_convert_encoding($url, $encoding);
}
}
$url = _unescape(trim($url));
list($scheme, $netloc, $path, $params, $query, $fragment) = _parse_url($url);
$keyvals = _parse_qsl($query, $keep_blank_values);
$keyvals = _delete_trash_keyvals($keyvals, $attributes, $exclude_attributes, $allow_value_list);
ksort($keyvals);
$query = _urlencode($keyvals);
$path = _safe_url_string(_unquotepath($path)) | '/';
$path = preg_replace('#/+#', '/', $path);
$fragment = $keep_fragments ? $fragment : '';
$data = array(
'scheme' => strtolower($scheme),
'netloc' => strtolower($netloc),
'path' => $path,
'params' => $params,
'query' => $query,
'fragment' => $fragment
);
return _urlunparse($data);
}
/**
* Возвращает относительный путь URL.
*
* @return string Относительный путь
*/
function _get_relative_url($url) {
$url = preg_replace('#https?://.*?(?:/|$)#i', '/', $url, 1);
$url = ltrim($url, '/');
return '/'.$url;
}
/**
* Custom hexdec function for greater numbers using BC Math.
*
* @link http://www.php.net/manual/en/book.bc.php BCMath Arbitrary Precision Mathematics
*
* @return string
*/
function bchexdec($hex) {
$dec = 0;
$len = strlen($hex);
for ($i = 1; $i <= $len; $i++) {
$dec = bcadd($dec, bcmul(strval(hexdec($hex[$i - 1])), bcpow('16', strval($len - $i))));
}
return $dec;
}
/**
* Custom hexdec function for greater numbers using GMP.
*
* @link http://www.php.net/manual/en/book.gmp.php GNU Multiple Precision
*
* @return string
*/
function gmp_hexdec($hex) {
$gmp = gmp_init(0);
$mult = gmp_init(1);
for ($i = strlen($hex) - 1; $i >= 0; $i--, $mult = gmp_mul($mult, 16)) {
$gmp = gmp_add($gmp, gmp_mul($mult, hexdec($hex[$i])));
}
return gmp_strval($gmp);
}
/**
* Custom hexdec function for greater numbers.
*
* @return string
*/
function hex2dec($s) {
if (!function_exists('number')) {
function number($param) {
return intval($param);
}
}
if (!function_exists('add')) {
function add($x, $y) {
$c = 0;
$r = array();
$x = array_map('number', str_split($x));
$y = array_map('number', str_split($y));
while (count($x) || count($y)) {
$s = (array_pop($x)) + (array_pop($y)) + $c;
array_unshift($r, $s < 10 ? $s : $s - 10);
$c = $s < 10 ? 0 : 1;
}
if ($c) {
array_unshift($r, $c);
}
return implode('', $r);
}
}
$dec = '0';
$s = str_split($s);
foreach($s as $chr) {
$n = intval($chr, 16);
for ($t = 8; $t; $t >>= 1) {
$dec = (string)add($dec, $dec);
if ($n & $t) {
$dec = (string)add($dec, '1');
}
}
}
return $dec;
}
/**
* Хэширует строку и усекает до 20 символов
*
* @return string Усеченная хешированная строка
*/
function _hash_string($string) {
if (function_exists('bcadd')) {
$string_hash = bchexdec(md5($string));
}
elseif (function_exists('gmp_add')) {
$string_hash = gmp_hexdec(md5($string));
}
else {
$string_hash = hex2dec(md5($string));
}
return substr($string_hash, 0, 18);
}
/**
* Возвращает хеш относительного URL.
* Новая функция, созданная для получения идентичных данных с python из КИТ.
*
* @return string Хеш относительного URL
*/
function _relative_url_hash($url, $r4_cfg_root='', $exclude_attributes=array()) {
$attributes = array();
$r4_knownparams = "{$r4_cfg_root}r4_knownparams.list";
if (file_exists($r4_knownparams)) {
$attributes = file($r4_knownparams);
if (is_array($attributes)) {
foreach ($attributes as $key => $attribute) {
$attributes[$key] = trim($attribute);
}
}
}
if (empty($exclude_attributes)) {
$r4_badparams = "{$r4_cfg_root}r4_badparams.list";
if (file_exists($r4_badparams)) {
$exclude_attributes = file($r4_badparams);
if (is_array($exclude_attributes)) {
foreach ($exclude_attributes as $key => $exclude_attribute) {
$exclude_attributes[$key] = trim($exclude_attribute);
}
}
}
}
$canonical_url = _canonicalize_url($url, true, false, 'UTF-8', $attributes, $exclude_attributes);
$relative_canonical_url = _get_relative_url($canonical_url);
return _hash_string($relative_canonical_url);
}
/**
* Старая функция
*
* @return string Хеш md5 от $url и его параметров
*/
function getHash($url, $r4_cfg_root) {
$u = parse_url(str_replace('&', '&', $url));
$kp = file("{$r4_cfg_root}r4_knownparams.list");
$known_params = array();
foreach ($kp as $K) {
$known_params[] = trim($K);
}
if (empty($u['path'])) {
$u['path'] = '/';
}
$hash = array();
$hash['=p'] = $u['path'];
if (!empty($u['query'])) {
$as = explode('&', $u['query']);
foreach ($as as $attr) {
$pair = explode('=', $attr);
if (!empty($pair)) {
$v = '';
$k = '';
if (!empty($pair[1])) {
if (preg_match('/[0-9a-fA-F]{32}/', $pair[1])) {
continue;
}
$v = $pair[1];
}
if (!empty($pair[0])) {
if (!in_array($pair[0], $known_params)) {
continue;
}
$k = $pair[0];
}
if (!isset($hash[$k])) {
$hash[$k] = array();
}
$hash[$k][] = $v;
}
}
}
ksort($hash);
$hash = md5(serialize($hash));
return $hash;
}