代码之家  ›  专栏  ›  技术社区  ›  Asur

如何在PHP中同时使用多种算法对文件进行哈希?

  •  2
  • Asur  · 技术社区  · 7 年前

    我想使用多种算法对给定文件进行哈希运算,但现在我按顺序进行,如下所示:

    return [
        hash_file('md5', $uri),
        hash_file('sha1', $uri),
        hash_file('sha256', $uri)
    ];
    

    是否要对只打开一个流而不是N的文件进行哈希处理,其中N是我要使用的算法量?类似这样:

    return hash_file(['md5', 'sha1', 'sha256'], $uri);
    
    2 回复  |  直到 7 年前
        1
  •  6
  •   Lawrence Cherone    7 年前

    您可以打开文件指针,然后使用 hash_init() 具有 hash_update() 要在不多次打开文件的情况下计算文件的哈希值,请使用 hash_final() 获取结果哈希。

    <?php
    function hash_file_multi($algos = [], $filename) {
        if (!is_array($algos)) {
            throw new \InvalidArgumentException('First argument must be an array');
        }
    
        if (!is_string($filename)) {
            throw new \InvalidArgumentException('Second argument must be a string');
        }
    
        if (!file_exists($filename)) {
            throw new \InvalidArgumentException('Second argument, file not found');
        }
    
        $result = [];
        $fp = fopen($filename, "r");
        if ($fp) {
            // ini hash contexts
            foreach ($algos as $algo) {
                $ctx[$algo] = hash_init($algo);
            }
    
            // calculate hash
            while (!feof($fp)) {
                $buffer = fgets($fp, 65536);
                foreach ($ctx as $key => $context) {
                    hash_update($ctx[$key], $buffer);
                }
            }
    
            // finalise hash and store in return
            foreach ($algos as $algo) {
                $result[$algo] = hash_final($ctx[$algo]);
            }
    
            fclose($fp);
        } else {
            throw new \InvalidArgumentException('Could not open file for reading');
        }   
        return $result;
    }
    
    $result = hash_file_multi(['md5', 'sha1', 'sha256'], $uri);
    
    var_dump($result['md5'] === hash_file('md5', $uri)); //true
    var_dump($result['sha1'] === hash_file('sha1', $uri)); //true
    var_dump($result['sha256'] === hash_file('sha256', $uri)); //true
    

    还发布到PHP手册: http://php.net/manual/en/function.hash-file.php#122549

        2
  •  2
  •   Ilmari Karonen hansTheFranz    7 年前

    以下是对 Lawrence Cherone的解决方案 *只读取文件一次,甚至适用于不可查找的流,如STDIN:

    <?php
    函数hash\u stream\u multi($algos=[],$stream){
    如果(!is\u数组($algos)){
    抛出new\InvalidArgumentException('第一个参数必须是数组');
    }
    
    如果(!is\u资源($流)){
    抛出new\InvalidArgumentException('第二个参数必须是资源');
    }
    
    $结果=[];
    foreach($algos as$algo){
    $ctx[$algo]=哈希初始化($algo);
    }
    而(!feof($stream)){
    $chunk=fread($stream,1<<20);//读取1个MiB块中的数据
    foreach($algos as$algo){
    哈希\u更新($ctx[$algo],$chunk);
    }
    }
    foreach($algos as$algo){
    $结果[$算法]=哈希\u最终值($ctx[$算法]);
    }
    返回$结果;
    }
    
    //测试:使用MD5、SHA-1和SHA-256输入哈希标准
    $结果=哈希\u流\u多(['md5',sha1',sha256',STDIN);
    print\u r($结果);
    
    
    

    它通过从输入流中读取数据来工作http://php.net/manual/en/function.fread.php“rel=“nofollow noreferrer”>fread()分块(1兆字节,这应该在性能和内存使用之间取得合理的平衡),并使用哈希更新()

    我写这篇文章时,劳伦斯更新了他的答案,但我觉得我的答案仍然足够清晰,可以同时保留这两个答案。此解决方案与Lawrence的更新版本之间的主要区别在于,我的函数采用的是输入流而不是文件名,并且我使用的是fread(),而不是fgets()(因为对于哈希,不需要在换行上拆分输入)

    在线试用!

    它的工作原理是使用 fread() 以块的形式(1兆字节,这应该在性能和内存使用之间取得合理的平衡),并使用 hash_update()

    *)劳伦斯在我写这篇文章的时候更新了他的答案,但我觉得我的答案仍然足够清晰,有理由保留这两个答案。此解决方案与Lawrence的更新版本之间的主要区别在于,我的函数采用的是输入流而不是文件名,并且我使用的是 fread() 而不是 fgets() (因为对于哈希,不需要在换行符上拆分输入)。