{"id":13462498,"url":"https://github.com/jenssegers/imagehash","last_synced_at":"2026-10-19T09:12:54.318Z","repository":{"id":24158765,"uuid":"27548713","full_name":"jenssegers/imagehash","owner":"jenssegers","description":"🌄 Perceptual image hashing for PHP","archived":false,"fork":false,"pushed_at":"2025-09-17T09:16:37.000Z","size":1371,"stargazers_count":2063,"open_issues_count":39,"forks_count":173,"subscribers_count":66,"default_branch":"master","last_synced_at":"2026-10-13T10:14:42.871Z","etag":null,"topics":["hash","image","image-hash","perceptual-hashes"],"latest_commit_sha":null,"homepage":"https://jenssegers.com","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jenssegers.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"jenssegers","tidelift":"packagist/jenssegers/imagehash"}},"created_at":"2014-12-04T16:18:33.000Z","updated_at":"2026-10-06T14:29:29.000Z","dependencies_parsed_at":"2024-03-04T15:14:30.176Z","dependency_job_id":"09d71cdd-bdac-4555-bff3-71b1040a1c03","html_url":"https://github.com/jenssegers/imagehash","commit_stats":{"total_commits":116,"total_committers":19,"mean_commits":6.105263157894737,"dds":0.3362068965517241,"last_synced_commit":"643d8d676c5cbe637199206476015e36548841f0"},"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"purl":"pkg:github/jenssegers/imagehash","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jenssegers%2Fimagehash","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jenssegers%2Fimagehash/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jenssegers%2Fimagehash/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jenssegers%2Fimagehash/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jenssegers","download_url":"https://codeload.github.com/jenssegers/imagehash/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jenssegers%2Fimagehash/sbom","scorecard":{"id":515144,"data":{"date":"2025-08-11","repo":{"name":"github.com/jenssegers/imagehash","commit":"643d8d676c5cbe637199206476015e36548841f0"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.9,"checks":[{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Code-Review","score":5,"reason":"Found 9/17 approved changesets -- score normalized to 5","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/main.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/jenssegers/imagehash/main.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/main.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/jenssegers/imagehash/main.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:34: update your workflow using https://app.stepsecurity.io/secureworkflow/jenssegers/imagehash/main.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/main.yml:53: update your workflow using https://app.stepsecurity.io/secureworkflow/jenssegers/imagehash/main.yml/master?enable=pin","Warn: containerImage not pinned by hash: docker/gd.Dockerfile:4","Warn: containerImage not pinned by hash: docker/gd.Dockerfile:5","Warn: containerImage not pinned by hash: docker/gmp.Dockerfile:4","Warn: containerImage not pinned by hash: docker/gmp.Dockerfile:5","Warn: containerImage not pinned by hash: docker/imagick.Dockerfile:4","Warn: containerImage not pinned by hash: docker/imagick.Dockerfile:5","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   2 third-party GitHubAction dependencies pinned","Info:   0 out of   6 containerImage dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE.md:0","Info: FSF or OSI recognized license: MIT License: LICENSE.md:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 22 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-20T01:36:51.571Z","repository_id":24158765,"created_at":"2025-08-20T01:36:51.571Z","updated_at":"2025-08-20T01:36:51.571Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":344872684,"owners_count":38352880,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-10-03T21:59:58.778Z","status":"online","status_checked_at":"2026-10-19T02:00:06.414Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hash","image","image-hash","perceptual-hashes"],"created_at":"2024-07-31T12:00:49.809Z","updated_at":"2026-10-19T09:12:54.070Z","avatar_url":"https://github.com/jenssegers.png","language":"PHP","funding_links":["https://github.com/sponsors/jenssegers","https://tidelift.com/funding/github/packagist/jenssegers/imagehash","https://www.paypal.me/jenssegers","https://tidelift.com/security"],"categories":["Uncategorized","Table of Contents","图像 Imagery","PHP","目录","Graphics and Media"],"sub_categories":["Uncategorized","Imagery","图像 Imagery","Image and Video","Globalization"],"readme":"ImageHash\n=========\n\n[![Latest Stable Version](http://img.shields.io/github/release/jenssegers/imagehash.svg)](https://packagist.org/packages/jenssegers/imagehash) [![Build Status](http://img.shields.io/travis/jenssegers/imagehash.svg)](https://travis-ci.org/jenssegers/imagehash) [![Coverage Status](http://img.shields.io/coveralls/jenssegers/imagehash.svg)](https://coveralls.io/r/jenssegers/imagehash) [![Donate](https://img.shields.io/badge/donate-paypal-blue.svg)](https://www.paypal.me/jenssegers)\n\n\u003e A perceptual hash is a fingerprint of a multimedia file derived from various features from its content. Unlike cryptographic hash functions which rely on the avalanche effect of small changes in input leading to drastic changes in the output, perceptual hashes are \"close\" to one another if the features are similar.\n\n\u003cp align=\"center\"\u003e\u003cimg src=\"https://jenssegers.com/static/media/fingerprint.png\"\u003e\u003c/p\u003e\n\nPerceptual hashes are a different concept compared to cryptographic hash functions like MD5 and SHA1. With cryptographic hashes, the hash values are random. The data used to generate the hash acts like a random seed, so the same data will generate the same result, but different data will create different results. Comparing two SHA1 hash values really only tells you two things. If the hashes are different, then the data is different. And if the hashes are the same, then the data is likely the same. In contrast, perceptual hashes can be compared -- giving you a sense of similarity between the two data sets.\n\nThis code was inspired/based on:\n - https://github.com/kennethrapp/phasher\n - http://www.phash.org\n - http://blockhash.io\n - http://www.hackerfactor.com/blog/?/archives/529-Kind-of-Like-That.html\n - http://www.hackerfactor.com/blog/?/archives/432-Looks-Like-It.html\n - http://blog.iconfinder.com/detecting-duplicate-images-using-python\n\nRequirements\n------------\n\n - PHP 8.1 or higher\n - The [gd](http://php.net/manual/en/book.image.php) or [imagick](http://php.net/manual/en/book.imagick.php) extension\n - Optionally, install the [GMP](http://php.net/manual/en/book.gmp.php) extension for faster fingerprint comparisons\n\nInstallation\n------------\n\n*This package has not reached a stable version yet, backwards compatibility may be broken between 0.x releases. Make sure to lock your version if you intend to use this in production!*\n\nInstall using composer:\n\n\tcomposer require jenssegers/imagehash\n\nUsage\n-----\n\nThe library comes with 4 built-in hashing implementations:\n\n - `Jenssegers\\ImageHash\\Implementations\\AverageHash` - Hash based the average image color\n - `Jenssegers\\ImageHash\\Implementations\\DifferenceHash` - Hash based on the previous pixel\n - `Jenssegers\\ImageHash\\Implementations\\BlockHash` - Hash based on blockhash.io **Still under development**\n - `Jenssegers\\ImageHash\\Implementations\\PerceptualHash` - The original pHash **Still under development**\n\nChoose one of these implementations. If you don't know which one to use, try the `DifferenceHash` implementation. Some implementations allow some configuration, be sure to check the constructor.\n\n```php\nuse Jenssegers\\ImageHash\\ImageHash;\nuse Jenssegers\\ImageHash\\Implementations\\DifferenceHash;\n\n$hasher = new ImageHash(new DifferenceHash());\n$hash = $hasher-\u003ehash('path/to/image.jpg');\n\necho $hash;\n// or\necho $hash-\u003etoHex();\n```\n\nThe resulting `Hash` object, is a hexadecimal image fingerprint that can be stored in your database once calculated. The hamming distance is used to compare two image fingerprints for similarities. Low distance values will indicate that the images are similar or the same, high distance values indicate that the images are different. Use the following method to detect if images are similar or not:\n\n```php\n$distance = $hasher-\u003edistance($hash1, $hash2);\n// or\n$distance = $hash1-\u003edistance($hash2);\n```\n\nEqual images will not always have a distance of 0, so you will need to decide at which distance you will evaluate images as equal. For the image set that I tested, a max distance of 5 was acceptable. But this will depend on the implementation, the images and the number of images. For example; when comparing a small set of images, a lower maximum distances should be acceptable as the chances of false positives are quite low. If however you are comparing a large amount of images, 5 might already be too much.\n\nThe `Hash` object can return the internal binary hash in a couple of different format:\n\n```php\necho $hash-\u003etoHex(); // 7878787c7c707c3c\necho $hash-\u003etoBits(); // 0111100001111000011110000111110001111100011100000111110000111100\necho $hash-\u003etoInt(); // 8680820757815655484\necho $hash-\u003etoBytes(); // \"\\x0F\\x07ƒƒ\\x03\\x0F\\x07\\x00\"\n```\n\nChoose your preference for storing your hashes in your database. If you want to reconstruct a `Hash` object from a previous calculated value, use:\n\n```php\n$hash = Hash::fromHex('7878787c7c707c3c');\n$hash = Hash::fromBin('0111100001111000011110000111110001111100011100000111110000111100');\n$hash = Hash::fromInt('8680820757815655484');\n```\n\nDemo\n----\n\nThese images are similar:\n\n![Equals1](https://raw.githubusercontent.com/jenssegers/imagehash/master/tests/images/forest/forest-high.jpg)\n![Equals2](https://raw.githubusercontent.com/jenssegers/imagehash/master/tests/images/forest/forest-copyright.jpg)\n\n\tImage 1 hash: 3c3e0e1a3a1e1e1e (0011110000111110000011100001101000111010000111100001111000011110)\n\tImage 2 hash: 3c3e0e3e3e1e1e1e (0011110000111110000011100011111000111110000111100001111000011110)\n\tHamming distance: 3\n\nThese images are different:\n\n![Equals1](https://raw.githubusercontent.com/jenssegers/imagehash/master/tests/images/office/tumblr_ndyfnr7lk21tubinno1_1280.jpg)\n![Equals2](https://raw.githubusercontent.com/jenssegers/imagehash/master/tests/images/office/tumblr_ndyfq386o41tubinno1_1280.jpg)\n\n\tImage 1 hash: 69684858535b7575 (0010100010101000101010001010100010101011001010110101011100110111)\n\tImage 2 hash: e1e1e2a7bbaf6faf (0111000011110000111100101101001101011011011101010011010101001111)\n\tHamming distance: 32\n\n## Security contact information\n\nTo report a security vulnerability, follow [these steps](https://tidelift.com/security).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjenssegers%2Fimagehash","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjenssegers%2Fimagehash","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjenssegers%2Fimagehash/lists"}