PHP code example of legitphp / hash-money

1. Go to this page and download the library: Download legitphp/hash-money library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

legitphp / hash-money example snippets


use LegitPHP\HashMoney\CompositeHash;

$composite = CompositeHash::default();
$hash = $composite->hashFromFile('/path/to/image.jpg');

echo $hash->getBits();     // 256
echo $hash->toHex();       // 64 hex chars
echo $hash->getAlgorithm();// "composite:perceptual+dhash+color-histogram+block-mean"

use LegitPHP\HashMoney\PerceptualHash;
use LegitPHP\HashMoney\DHash;
use LegitPHP\HashMoney\ColorHistogramHash;
use LegitPHP\HashMoney\MashedHash;
use LegitPHP\HashMoney\PdqHash;

// Generate a perceptual hash
$pHash = PerceptualHash::hashFromFile('/path/to/image.jpg');
echo $pHash->toHex(); // e.g., "f0e1d2c3b4a59687"

// Generate a difference hash  
$dHash = DHash::hashFromFile('/path/to/image.jpg');
echo $dHash->toBinary(); // e.g., "1010101100110011..."

// Generate a color histogram hash
$colorHash = ColorHistogramHash::hashFromFile('/path/to/image.jpg');
echo $colorHash->toHex(); // e.g., "a1b2c3d4e5f6g7h8"

// Generate a MashedHash (comprehensive fingerprint)
$mHash = MashedHash::hashFromFile('/path/to/image.jpg');
echo $mHash->toHex(); // e.g., "1cf0e2a3b4596d87"

// Generate a PDQ hash (256-bit, with quality score)
$pdqHash = PdqHash::hashFromFile('/path/to/image.jpg');
echo $pdqHash->toHex(); // 64 hex chars
echo PdqHash::quality($pdqHash); // 0-100; Meta recommends discarding < 50

// Compare images
$hash1 = PerceptualHash::hashFromFile('/path/to/image1.jpg');
$hash2 = PerceptualHash::hashFromFile('/path/to/image2.jpg');
$distance = PerceptualHash::distance($hash1, $hash2);

if ($distance <= 10) {
    echo "Images are very similar!";
}

// Generate different sized hashes for different use cases
$hash64 = PerceptualHash::hashFromFile($path, 64); // Default, most accurate
$hash32 = PerceptualHash::hashFromFile($path, 32); // Balanced speed/accuracy
$hash16 = PerceptualHash::hashFromFile($path, 16); // Fast, basic matching
$hash8 = PerceptualHash::hashFromFile($path, 8);   // Extremely fast, rough matching

// Same options available for DHash
$dHash = DHash::hashFromFile($path, 32);

// The API returns HashValue objects with type safety
$pHash = PerceptualHash::hashFromFile('image.jpg');
$dHash = DHash::hashFromFile('image.jpg');

// This will throw an exception - can't compare different algorithms!
try {
    PerceptualHash::distance($pHash, $dHash);
} catch (InvalidArgumentException $e) {
    echo "Cannot compare hashes from different algorithms";
}

// Get hash details
echo $pHash->getValue();     // Raw integer value
echo $pHash->getBits();      // 64
echo $pHash->getAlgorithm(); // "perceptual"
echo $pHash->toHex();        // Hexadecimal representation

// Create typed HashValue instances from various sources
$fromHex = HashValue::fromHex('a1b2c3d4', 32, 'perceptual');
$fromBinary = HashValue::fromBinary('10101010', 'dhash');
$fromBase64 = HashValue::fromBase64('EjRWeQ==', 32, 'color-histogram');

// Type safety is maintained across all operations
if ($pHash->isCompatibleWith($fromHex)) {
    $distance = $pHash->hammingDistance($fromHex);
}

// Configure VIPS settings for performance tuning
PerceptualHash::configure([
    'cores' => 4,
    'maxCacheSize' => 100,  // Max cached operations
    'maxMemory' => 256,     // 256MB cache memory
]);

// Each strategy maintains its own configuration
DHash::configure([
    'cores' => 8,
]);

// Configure Color Histogram Hash quantization
ColorHistogramHash::configureQuantization(16, 8, 8); // 16 hue bins, 8 saturation bins, 8 value bins

// MashedHash uses standard VIPS configuration
MashedHash::configure([
    'cores' => 4,
]);

use LegitPHP\HashMoney\HashValue;
use LegitPHP\HashMoney\PerceptualHash;

$hash = PerceptualHash::hashFromFile('image.jpg');

// Basic information
$value = $hash->getValue();        // Raw integer value
$hex = $hash->toHex();            // Hex representation (e.g., "a1b2c3d4e5f6")
$binary = $hash->toBinary();      // Binary string (e.g., "101010110010...")
$bits = $hash->getBits();         // Size in bits (8, 16, 32, or 64)
$algorithm = $hash->getAlgorithm(); // Algorithm name

// Additional representations
$base64 = $hash->toBase64();           // Base64 encoding
$urlSafe = $hash->toUrlSafeBase64();  // URL-safe base64
$string = (string) $hash;             // Converts to hex

// Direct comparison
if ($hash1->equals($hash2)) {
    echo "Exact match!";
}

// Calculate distance directly
$distance = $hash1->hammingDistance($hash2);
echo "Images differ by $distance bits";

// Process multiple images efficiently
$images = glob('/path/to/images/*.jpg');
$hashes = [];

foreach ($images as $image) {
    $hashes[$image] = DHash::hashFromFile($image, 32);
}

// Find similar images
foreach ($hashes as $path1 => $hash1) {
    foreach ($hashes as $path2 => $hash2) {
        if ($path1 !== $path2 && DHash::distance($hash1, $hash2) < 10) {
            echo "$path1 is similar to $path2\n";
        }
    }
}

// Configure for maximum performance
PerceptualHash::configure([
    'cores' => 8,              // Use 8 CPU cores
    'maxMemory' => 512,        // 512MB cache memory
    'disableCache' => false,   // Enable caching
]);

// Each strategy has independent configuration
DHash::configure([
    'cores' => 4,
    'maxMemory' => 256,        // 256MB cache memory
]);

// Process from memory to avoid disk I/O
$imageData = file_get_contents('large-image.jpg');
$hash = PerceptualHash::hashFromString($imageData);

use LegitPHP\HashMoney\HashValue;

// Create from hexadecimal string
$fromHex = HashValue::fromHex('a1b2c3d4e5f6', 64, 'perceptual');
$fromHex = HashValue::fromHex('0xA1B2C3D4E5F6', 64, 'perceptual'); // With prefix

// Create from binary string
$fromBinary = HashValue::fromBinary('10101010', 'dhash'); // Auto-detects 8-bit

// Create from base64
$fromBase64 = HashValue::fromBase64('EjRWeJCrze8=', 64, 'perceptual');

// Serialize to different formats
$hash = PerceptualHash::hashFromFile('image.jpg');
$json = json_encode($hash); // Implements JsonSerializable
$array = $hash->toArray();  // Convert to array

// Restore from serialized data
$decoded = json_decode($json, true);
$restored = HashValue::fromArray($decoded);

// Create hash with metadata
$hash = PerceptualHash::hashFromFile('photo.jpg');
$hashWithMeta = $hash->withMetadata([
    'filename' => 'photo.jpg',
    'timestamp' => time(),
    'source' => 'user_upload',
    'quality_score' => 0.95
]);

// Access metadata
$allMeta = $hashWithMeta->getMetadata();
$filename = $hashWithMeta->getMetadata('filename');

// Metadata persists through serialization
$json = json_encode($hashWithMeta->toArray());
$restored = HashValue::fromArray(json_decode($json, true));
echo $restored->getMetadata('filename'); // 'photo.jpg'

$hash = DHash::hashFromFile('image.jpg', 64);

// Check individual bits
for ($i = 0; $i < 8; $i++) {
    if ($hash->getBit($i)) {
        echo "Bit $i is set\n";
    }
}

// Count set bits (useful for hash analysis)
$setBits = $hash->countSetBits();
$density = $setBits / $hash->getBits(); // Bit density ratio

// Get normalized value (0.0 to 1.0)
$normalized = $hash->normalized();

$hash1 = PerceptualHash::hashFromFile('original.jpg');
$hash2 = PerceptualHash::hashFromFile('modified.jpg');

// Direct Hamming distance calculation
$distance = $hash1->hammingDistance($hash2);

// Calculate similarity percentage
$maxDistance = $hash1->getBits();
$similarity = (1 - ($distance / $maxDistance)) * 100;
echo "Images are {$similarity}% similar";

// Use normalized values for threshold comparisons
if ($hash1->normalized() > 0.5 && $hash2->normalized() > 0.5) {
    echo "Both images have high bit density";
}

use LegitPHP\HashMoney\MultiIndexHash;

$hash = PerceptualHash::hashFromFile('image.jpg');
$chunks = MultiIndexHash::chunks($hash, 8); // 8 × 8-bit chunks, safe for k ≤ 7

// Persist chunks as BIGINT columns (mih_0..mih_7), each with its own index
// ... then query:
//   SELECT * FROM hashes
//   WHERE mih_0=? OR mih_1=? OR mih_2=? ... OR mih_7=?
// Union is your candidate set; verify with hammingDistance() in PHP.

use LegitPHP\HashMoney\CompositeHash;
use LegitPHP\HashMoney\Lsh;

$composite = CompositeHash::default();
$hash = $composite->hashFromFile('image.jpg');

// 4 bands per chunk → 16 total bucket keys for the 256-bit quartet.
$bucketKeys = Lsh::bandsByChunk($hash, bandsPerChunk: 4);
// [
//   'perceptual'       => [k1, k2, k3, k4],
//   'dhash'            => [k5, k6, k7, k8],
//   'color-histogram'  => [k9, k10, k11, k12],
//   'block-mean'       => [k13, k14, k15, k16],
// ]

// Flat banding (no chunk awareness):
$flatKeys = Lsh::bands($hash, bandCount: 16);

// Storing in database
$hash = MashedHash::hashFromFile('product-image.jpg');
$data = [
    'image_id' => 12345,
    'hash_value' => $hash->getValue(),      // Store as BIGINT
    'hash_hex' => $hash->toHex(),          // Store as CHAR(16) for 64-bit
    'algorithm' => $hash->getAlgorithm(),   // Store algorithm type
    'metadata' => json_encode([
        'original_name' => 'product-image.jpg',
        'processed_at' => date('Y-m-d H:i:s')
    ])
];

// Retrieving from database
$row = $db->fetchRow("SELECT * FROM image_hashes WHERE image_id = ?", [12345]);
$hash = new HashValue(
    $row['hash_value'],
    64,
    $row['algorithm'],
    json_decode($row['metadata'], true)
);

// Or use hex value
$hash = HashValue::fromHex($row['hash_hex'], 64, $row['algorithm']);

// Sending hash data
$hash = ColorHistogramHash::hashFromFile('image.jpg');
$apiPayload = [
    'image_hash' => $hash->toUrlSafeBase64(), // URL-safe for GET requests
    'algorithm' => $hash->getAlgorithm(),
    'bits' => $hash->getBits()
];

$response = $httpClient->post('/api/check-duplicate', [
    'json' => $apiPayload
]);

// Receiving and reconstructing
$data = json_decode($response->getBody(), true);
$receivedHash = HashValue::fromBase64(
    $data['image_hash'],
    $data['bits'],
    $data['algorithm']
);

class ImageDuplicateDetector 
{
    private array $hashDatabase = [];
    
    public function addImage(string $path): void 
    {
        // Generate multiple hash types for robust matching
        $pHash = PerceptualHash::hashFromFile($path);
        $dHash = DHash::hashFromFile($path);
        $mHash = MashedHash::hashFromFile($path);
        
        // Store with metadata
        $this->hashDatabase[$path] = [
            'perceptual' => $pHash->withMetadata(['path' => $path]),
            'dhash' => $dHash->withMetadata(['path' => $path]),
            'mashed' => $mHash->withMetadata(['path' => $path]),
            'added_at' => time()
        ];
    }
    
    public function findDuplicates(string $imagePath, int $threshold = 10): array 
    {
        $candidates = [];
        $testHashes = [
            'perceptual' => PerceptualHash::hashFromFile($imagePath),
            'dhash' => DHash::hashFromFile($imagePath),
            'mashed' => MashedHash::hashFromFile($imagePath)
        ];
        
        foreach ($this->hashDatabase as $storedPath => $storedHashes) {
            $scores = [
                'perceptual' => $testHashes['perceptual']->hammingDistance($storedHashes['perceptual']),
                'dhash' => $testHashes['dhash']->hammingDistance($storedHashes['dhash']),
                'mashed' => $testHashes['mashed']->hammingDistance($storedHashes['mashed'])
            ];
            
            // Weighted scoring
            $totalScore = ($scores['perceptual'] * 2 + $scores['dhash'] + $scores['mashed']) / 4;
            
            if ($totalScore <= $threshold) {
                $candidates[] = [
                    'path' => $storedPath,
                    'score' => $totalScore,
                    'individual_scores' => $scores
                ];
            }
        }
        
        // Sort by similarity
        usort($candidates, fn($a, $b) => $a['score'] <=> $b['score']);
        
        return $candidates;
    }
}

// Use MashedHash + pHash for best results
$mHash = MashedHash::hashFromFile($image);
$pHash = PerceptualHash::hashFromFile($image);

if (MashedHash::distance($mHash1, $mHash2) < 20 && 
    PerceptualHash::distance($pHash1, $pHash2) < 12) {
    // High confidence match
}

// Use all three spatial/color hashes
$pHash = PerceptualHash::hashFromFile($image);
$dHash = DHash::hashFromFile($image);
$colorHash = ColorHistogramHash::hashFromFile($image);

// One 256-bit composite instead of four separate hashes — lets you
// band-index each chunk and do indexed candidate generation in the DB.
$composite = CompositeHash::default();
$hash = $composite->hashFromFile($image);
$bucketKeys = Lsh::bandsByChunk($hash, bandsPerChunk: 4);

use LegitPHP\HashMoney\PdqHash;
use LegitPHP\HashMoney\Strategies\PdqHashStrategy;

$hash = PdqHash::hashFromFile($image);
$quality = PdqHash::quality($hash);

// Meta's recommended thresholds
if ($quality < PdqHashStrategy::RECOMMENDED_QUALITY_THRESHOLD) {
    // Image hashes unreliably (uniform / blurry) — skip or fall back to MashedHash.
    return null;
}

if (PdqHash::distance($hash, $candidate) <= PdqHashStrategy::RECOMMENDED_DISTANCE_THRESHOLD) {
    // Near-duplicate (≤ 31 of 256 bits differ).
}

// Catch rotated / flipped duplicates by hashing all eight dihedral variants once
// and matching the candidate's "orig" hash against any of them.
$variants = PdqHash::hashesFromFile($image);
foreach ($variants['hashes'] as $name => $variantHash) {
    if (PdqHash::distance($variantHash, $candidate) <= 31) {
        // Match under transform "$name" (orig / r090 / r180 / r270 / flpx / flpy / flpp / flpm).
    }
}