diff --git a/src/ImageHash.php b/src/ImageHash.php index 55ea5f8..1bed620 100644 --- a/src/ImageHash.php +++ b/src/ImageHash.php @@ -113,8 +113,8 @@ public function distance($hash1, $hash2) } } else { if ($this->mode === self::HEXADECIMAL) { - $hash1 = hexdec($hash1); - $hash2 = hexdec($hash2); + $hash1 = $this->hexdec($hash1); + $hash2 = $this->hexdec($hash2); } $dh = 0; @@ -129,6 +129,22 @@ public function distance($hash1, $hash2) return $dh; } + /** + * Convert hexadecimal to signed decimal. + * + * @param string $hex + * @return int + */ + public function hexdec($hex) + { + if (strlen($hex) == 16 && hexdec($hex[0]) > 8) { + list($higher, $lower) = array_values(unpack('N2', hex2bin($hex))); + return $higher << 32 | $lower; + } + + return hexdec($hex); + } + /** * Get a GD2 resource from file. * diff --git a/tests/ImageHashTest.php b/tests/ImageHashTest.php index 140eee6..784f8ae 100644 --- a/tests/ImageHashTest.php +++ b/tests/ImageHashTest.php @@ -31,4 +31,26 @@ public function testHashStringSameAsFile() $this->assertSame($this->imageHash->hash($path), $this->imageHash->hashFromString(file_get_contents($path))); } + + public function testHexdecForNegativeIntegers() + { + // native hexdec dechex conversion working for positive integers + $this->assertEquals(1, hexdec(dechex(1))); + // but not working for negative + $this->assertNotEquals(-1, hexdec(dechex(-1))); + + // custom hexdec implementation works for both + $this->assertEquals(1, $this->imageHash->hexdec(dechex(1))); + $this->assertEquals(-1, $this->imageHash->hexdec(dechex(-1))); + } + + public function testDistanceOfNegativeHashes() + { + $imageHash = new ImageHash(null, ImageHash::HEXADECIMAL); + $hash1 = 'ffffffffffffffff'; // -1 + $hash2 = 'fffffffffffffff0'; // -16 + + $distance = $imageHash->distance($hash1, $hash2); + $this->assertEquals(4, $distance); + } }