dsentker/url-fingerprint

从URL构建哈希值

0.4.0 2021-08-03 11:07 UTC

This package is auto-updated.

Last update: 2024-09-24 16:28:25 UTC


README

一个从URL创建唯一哈希值的库 - 而不会让你头疼。

此库旨在从URL获取唯一但一致的摘要(哈希结果),无论是否有副作用。即使在查询字符串中的参数顺序不同或URL包含如%20之类的编码字符,它也会生成相同的哈希结果。

此库使用“指纹”的概念。根据您的设置,为每个URL生成一个特定的指纹,其中包含摘要、哈希算法和URL的哈希部分。

基本用法

$reader = new FingerprintReader([
    'secret' => 's3cre7v4lu3',
]);
$fingerprint1 = $reader->capture('http://www.example.com/info?id=42&details');

// Same URL, but different parameter order in query string.
$fingerprint2 = $reader->capture('http://www.example.com/info?details&id=42'); 

$reader->compare($fingerprint1, $fingerprint2); // bool(true)

echo $fingerprint1->digest; // d7335d0a237f47a049415a780c4e1c96
echo $fingerprint2->digest; // d7335d0a237f47a049415a780c4e1c96 - the same

安装与使用

需要Composer 2和PHP >= 7.4。

使用Composer安装url-fingerprint。

composer require dsentker/url-fingerprint
# Create a FingerprintReader instance and provide options in the
# constructor (the `secret` parameter is required).
$reader = new \UrlFingerprint\FingerprintReader([
    'secret' => '42',
    'hash_algo' => 'md5'
]);

# Capture a new fingerprint by given URL
$fingerprint = $reader->capture('http://www.github.com/');

echo $fingerprint->digest; // the result from the hash process
echo $fingerprint->hashAlgo; // md5
echo $fingerprint->gist; // a JSON representation of the url parts

# Use the compare method to test against another fingerprint 
$reader->compare($fingerprint, $reader->capture('http://github.com'));

选项

在构造函数中配置选项以指定摘要的创建方式

示例

$reader = new \UrlFingerprint\FingerprintReader([
    'secret' => 's3cre7v4lu3',
    'ignore_host' => false,
]);
// Different hosts, but not part of the fingerprint. So both digest values are equal.
$fingerprint1 = $reader->capture('http://www.example.com/?foo');
$fingerprint2 = $reader->capture('http://www.example.net/?foo');
$reader->compare($fingerprint1, $fingerprint2); // true
$reader = new \UrlFingerprint\FingerprintReader([
    'secret' => 's3cre7v4lu3',
    'ignore_fragment' => true,
]);
// Create fingerprints for two equal URLs except the fragment
$fingerprint1 = $reader->capture('https://www.example.com/?foo');
$fingerprint2 = $reader->capture('https://www.example.com/?foo#bar');

// Fingerprints are not the same - The fragment part of the URL is taken into account. 
$reader->compare($fingerprint1, $fingerprint2); // false
// Define query string keys which should be ignored and pass it as 2nd argument in the capture method.
$ignoreQuery = ['foo', 'baz'];

$fingerprint1 = $reader->capture('https://www.example.com/detail');
$fingerprint2 = $reader->capture('https://www.example.com/detail?foo=bar', $ignoreQuery);

// Fingerprints are equal because the 'foo' parameter is ignored
$reader->compare($fingerprint1, $fingerprint2); // true

测试

使用PHPUnit: $ ./vendor/bin/phpunit tests

贡献

如果您发现错误,有一般性问题或想实现一个功能,欢迎您合作。

请参阅CONTRIBUTING以获取详细信息。

背景

动机

从URL生成唯一哈希值很有用,例如,当缓存API响应或出于安全目的时。简单地对URL进行哈希处理的想法可能变成一项艰巨的任务。考虑以下示例

$urlHash = hash('md5', 'https://example.com/index.php?foo=bar&qux');

这会创建相同的哈希值(摘要)每次。但如果查询字符串参数的顺序改变呢?

$url1 = 'https://example.com/index.php?foo=bar&qux';
$url2 = 'https://example.com/index.php?qux&foo=bar';

hash_equals(
    hash('md5', $url1),
    hash('md5', $url2)
); // false :-(

这两个URL在技术上都是相同的,但生成的摘要不同。

URL中还有更多部分您可能不想包含在哈希算法中

$url = 'https://example.com/#logo'; // Anchor / fragment appended
$url = 'http://example.com/'; // Different protocol
$url = 'https://example.com/?'; // Empty query string / No key/value groups

根据您的要求,这三个URL可能非常相似,因此应该生成相同的哈希结果。这正是此库的构建目的。在URL中还有其他不应影响URL哈希值的事物

  • 查询参数的顺序不同
  • 使用另一种协议
  • 应考虑URL编码字符,如%20

前身

此库取代了前身,即url-signature库

与url-signature库相比,此库已完全重写,并应解决以下缺点

  • url-signature库没有遵循单一职责原则
  • 查询字符串中的数组可能导致意外结果
  • 我不喜欢使用位掩码标志设置选项
  • 不需要对查询字符串进行规范的薄包装器
  • 调试哈希过程的研究可能性不足