V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Reign
V2EX  ›  程序员

为什么这段 PHP 代码在 php7.1 和 php5.5 中执行不一样?

  •  2
     
  •   Reign · 2017-06-01 09:02:39 +08:00 · 3422 次点击
    这是一个创建于 2725 天前的主题,其中的信息可能已经有所发展或是发生改变。

    网上一段计算图片 pHash(perceptual hash)的 php 代码,我把它更改了一下:

    function phash(file)
    {
    	$resource=imagecreatefromstring(file_get_contents($file));
        $size=8;
        $width = $size + 1;
        $heigth = $size;
        $resized = imagecreatetruecolor($width, $heigth);
        imagecopyresampled($resized, $resource, 0, 0, 0, 0, $width, $heigth, imagesx($resource), imagesy($resource));
        $hash = 0;
        $one = 1;
        for ($y = 0; $y < $heigth; $y++) {
            $rgb = imagecolorsforindex($resized, imagecolorat($resized, 0, $y));
            $left = floor(($rgb['red'] + $rgb['green'] + $rgb['blue']) / 3);
            for ($x = 1; $x < $width; $x++) {
                $rgb = imagecolorsforindex($resized, imagecolorat($resized, $x, $y));
                $right = floor(($rgb['red'] + $rgb['green'] + $rgb['blue']) / 3);
                if ($left > $right) {
                    $hash |= $one;
                }
                $left = $right;
                $one = $one << 1;
            }
        }
        imagedestroy($resized);
        return dechex($hash);
    }
    

    不知道 pHash 的同学可以先 Google 一下概念,上面的代码是我微改后的代码,原理貌似还是很好理解,就是把一张图片压缩成 8x8 的图片并计算 64 个像素灰度平均值,然后遍历每个像素和这个平均值比较,生成一个布尔值最后返回这个值的 16 进制,但是目前在两种环境下测试:

    1. centos 6.5 32 位 php5.5 的环境下,生成的 pHash 是 8 位,比如:a0e1c3c1
    2. centos 7.0 64 位 php7.1 的环境下,生成的 pHash 是 16 位,比如:fee6ccf4b133a9e9 这是何解

    因为源代码里面有点不懂:

    1. $hash |= $one;
    2. $one = $one << 1; 这两行代码什么意思?特别是“|=”这个符号半天都 Google 不到什么意思?求好心 V 友解疑释惑以下,不胜感激
    11 条回复    2017-06-01 11:03:06 +08:00
    Mitt
        1
    Mitt  
       2017-06-01 09:08:51 +08:00
    | 是异或 |= 是 $hash = $hash | $one 你需要查 PHP.net
    WytheHuang
        2
    WytheHuang  
       2017-06-01 09:11:12 +08:00
    Mitt
        3
    Mitt  
       2017-06-01 09:12:56 +08:00
    @Mitt 说错了 是位或 习惯了。。 ^ 是位异或
    mcfog
        4
    mcfog  
       2017-06-01 10:08:42 +08:00
    应该不是 php 版本的问题,而是 32 位 64 位的关系,32 位的整数转换成 hex 最大就是 8 位,你这个算法用 32 位的机器跑相当于直接溢出了

    要测试也很简单,在你 32 位的机器上装个 7,在 64 位机器上装个 5 交叉试一下就知道了

    如果要支持 32 位机器,或者更大的 size,可以在内层循环就 dechex 一下用字符串拼接来累计结果,而不是整数
    Reign
        5
    Reign  
    OP
       2017-06-01 10:10:43 +08:00
    @mcfog 谢谢,那请问,我两台服务器想保持 phash 一致,在不更改现有系统情况下,该怎么做呢
    we3613040
        6
    we3613040  
       2017-06-01 10:22:49 +08:00
    循环是 8*8 =64 次,会出现两个结果是那个 if 条件的问题,不过按道理说,这种 api 不应该会出现版本差异
    sagaxu
        7
    sagaxu  
       2017-06-01 10:23:41 +08:00
    @Reign 自己定死 hash 为 4 字节
    Reign
        8
    Reign  
    OP
       2017-06-01 10:28:20 +08:00
    @mcfog 即使不转成 16 进制,同一张图片,32 位 php5.5 得出的结果是:5779363675144030163,64 位 php7.1 得出结果为:1690404819
    Reign
        9
    Reign  
    OP
       2017-06-01 10:29:16 +08:00
    @sagaxu 谢谢,不太理解,怎么定死 hash 为 4 字节?
    Reign
        10
    Reign  
    OP
       2017-06-01 10:30:05 +08:00
    @mcfog 抱歉写反了:32 位 php5.5 得出的结果是:1690404819,64 位 php7.1 得出结果为:5779363675144030163
    sagaxu
        11
    sagaxu  
       2017-06-01 11:03:06 +08:00
    @Reign 用 int[],自己操控,4 字节为单位
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1443 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 17:35 · PVG 01:35 · LAX 09:35 · JFK 12:35
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.