在Windows、Linux和Mac上为同一图像创建的哈希值不同。

12

我使用以下代码创建哈希值,但现在的情况是,当我在Windows本地Xampp服务器上测试哈希值时,对于同一代码在Linux上运行时得到的哈希值不同。

  move_uploaded_file($_FILES["file"]["tmp_name"], "upload/" . $newname);
    "Stored in: " . "upload/" . $_FILES["file"]["name"];
    $image = "upload/" . $newname;
    $sign = md5(file_get_contents($image));

现在我不知道为什么会发生这种情况。对于刚刚粘贴的相同代码。

编辑:重新打开问题。我找到的解决方案只适用于Linux,这意味着Linux和Windows现在给出了相同的哈希值,但是当从Mac(IOS)上传图像时,它仍然会生成不同的哈希值。


2
这是同一个文件且行尾相同吗?在两个系统上运行md5sum是否返回相同的哈希值? - scai
只需使用任意字符串进行测试,例如 md5('hello');。这两个系统都匹配吗? - Ohgodwhy
可能是一篇有趣的阅读:http://ubuntuforums.org/showthread.php?t=1941596 - Fluffeh
@Fluffeh:我粗略地查看了你的链接,它讲解了关于Linux权限的命令,但这并不能从代码角度解决它 - noobie-php
如果在每个平台上运行md5命令行工具,对于您在磁盘上拥有的文件,它会显示什么?它与您在PHP中生成的哈希值有何区别? - Jon Skeet
显示剩余5条评论
4个回答

12

Windows和Linux具有不同的换行符,\r\n\n。因此,在读取文件时,文件内容是不同的。

尝试上传没有换行符或二进制文件的文本文件。还要检查读取的字节数的差异。它应该等于下一个文件中换行符的数量。


非常感谢你,实际上你在技术上引导了我找到了问题所在,但我仍然希望得到解决方案。 - noobie-php
1
个人而言,我不建议这样做。由于这两个文件基本上是不同的,它们应该具有不同的校验和。您可以按照 https://dev59.com/THRB5IYBdhLWcg3wZmlz 中所述的方法检查文件是否为 ASCII 或二进制文件,然后将 \r\n 转换为 \n,如 https://dev59.com/0GLVa4cB1Zd3GeqP0NU6 所示。现在检查转换后字符串的校验和。 - Sharad D
对我而言问题在于我的单元测试使用了一个带有CRLF行结尾的JSON文件,在Windows上能运行,但在Ubuntu代理上失败了,将JSON文件的行结尾更改为CRLF就解决了。 - Mohammad Sepahvand

8

好的,我找到了关于我的问题的答案,但我仍然不知道为什么在Windows和Linux中相同的代码会生成两个不同的哈希值。

move_uploaded_file($_FILES["file"]["tmp_name"], "upload/" . $newname); 
    "Stored in: " . "upload/" . $_FILES["file"]["name"];
    $image = "upload/" . $newname;
    $sign = md5(file_get_contents($image));//This is code block that i was implmenting before solution

我尝试的是用以下代码替换上面的代码。
 move_uploaded_file($_FILES["file"]["tmp_name"], "upload/" . $newname);
        "Stored in: " . "upload/" . $_FILES["file"]["name"];
        $image = "upload/" . $newname;
        $sign = md5_file($image);// Changed here

从这里我认为,当使用md5()生成哈希值时,哈希值可能相同,但如果此函数接受文件作为输入,则哈希值会以不同的方式计算。我不知道这是PHP方面的问题还是操作系统级别的问题,但如果我继续使用md5_file()来生成文件的哈希值,我就不会得到不同的哈希值。

我的猜测是file_get_contents()在不同平台上的行为不同。可能是与区域设置有关的问题?我不确定如何测试这个假设,:-/ - burlyearly
你现在的“答案”是仅对文件名进行哈希而不是内容。这有什么意义呢?我强烈认为你真正想要哈希的是内容。 - Jon Skeet
1
@JonSkeet:确切地说,文件名不是问题,问题实际上是生成哈希。如果你指的是md5_file($image),那么实际上被哈希的并不是文件名,而是文件本身。 - noobie-php
是的,实际上答案和问题都是由我提供的,所以如果有人想查看,他们必须同时查看两者。 - noobie-php

0

要获得与在Mac上使用类似以下命令生成的相同哈希值:

shasum -a 256 -p {filename} | cut -d' ' -f1"

请将{filename}替换为您要在Mac上进行哈希处理的文件名。| cut -d' ' -f1从返回的内容末尾剪切文件名,因为我们只关心哈希值。

在Windows上获得相同的哈希值,您需要执行以下操作:

获取文件流并调用我制作的此函数:

public static string GetSha256Checksum(this Stream stream)
    {
        stream.Rewind();
        using (var sha256 = SHA256Cng.Create())
        {
            return string.Concat(
                sha256.ComputeHash(stream)
                    .Select(item => item.ToString("x2"))
            );
        }
    }

当创建哈希以与MAC相同时,这是根本不同的地方:

string.Concat(sha256.ComputeHash(stream)
              .Select(item => item.ToString("x2"))

-1

可能需要查看 fopen() 页面以了解如何避免换行符问题,但基本上只需要在写入和读取文件时使用 'wb' 和 'rb'。这是 fopen 页面 的链接。

这意味着可能无法使用 file_get_content(),因为似乎没有选项来设置读取模式。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接