├── .github └── workflows │ ├── build.yml │ └── release.yml ├── .gitignore ├── LICENSE ├── README.md ├── composer.json ├── phpunit.php ├── phpunit.xml ├── src └── HashPlugin.php └── tests ├── HashPluginTest.php └── files ├── file1.txt ├── file2.txt └── file3.txt /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | pull_request: 5 | push: 6 | 7 | jobs: 8 | test: 9 | runs-on: ubuntu-latest 10 | strategy: 11 | matrix: 12 | php-versions: ['7.3', '7.4', '8.0'] 13 | name: PHP ${{ matrix.php-versions }} Test 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v2 17 | 18 | - name: Setup PHP 19 | uses: shivammathur/setup-php@v2 20 | with: 21 | php-version: ${{ matrix.php-versions }} 22 | coverage: xdebug 23 | 24 | - name: Install dependencies 25 | run: composer install 26 | 27 | - name: Run phpunit 28 | run: vendor/bin/phpunit 29 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: release 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*.*.*' 7 | 8 | jobs: 9 | release: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v2 14 | 15 | - name: Create Release 16 | id: create_release 17 | uses: actions/create-release@v1 18 | env: 19 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 20 | with: 21 | tag_name: ${{ github.ref }} 22 | release_name: ${{ github.ref }} 23 | draft: false 24 | prerelease: false 25 | 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | composer.phar 2 | .idea 3 | vendor 4 | composer.lock 5 | coverage 6 | coverage.xml 7 | test.php 8 | .phpunit.result.cache 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Entertainment Media Group AG 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Flysystem Plugin for generating hash value of file 2 | 3 | ![build](https://github.com/emgag/flysystem-hash/workflows/build/badge.svg) 4 | [![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](LICENSE) 5 | [![Packagist Version](https://img.shields.io/packagist/v/emgag/flysystem-hash.svg)](https://packagist.org/packages/emgag/flysystem-hash) 6 | 7 | **NOTE: Plugins were [removed in Flysystem 2.0](https://flysystem.thephpleague.com/v2/docs/what-is-new/) and thus this library is only available for Flysystem 1.x.** 8 | 9 | A plugin for the [Flysystem](https://github.com/thephpleague/flysystem) file 10 | system abstraction library to generate hash values of a file. See [hash_algos()](http://php.net/manual/en/function.hash-algos.php) function for supported hash algorithms. 11 | 12 | Tested with [Local](http://flysystem.thephpleague.com/adapter/local/) and [WebDav](http://flysystem.thephpleague.com/adapter/webdav/) adapters, but as the hash is built directly from the stream resource it should work for all other adapters as well. 13 | 14 | ## Installation 15 | 16 | ```bash 17 | composer require emgag/flysystem-hash 18 | ``` 19 | 20 | ## Usage 21 | 22 | ```php 23 | use Emgag\Flysystem\Hash\HashPlugin; 24 | use League\Flysystem\Adapter\Local; 25 | use League\Flysystem\Filesystem; 26 | 27 | $fs = new Filesystem(new Local(__DIR__)); 28 | $fs->addPlugin(new HashPlugin); 29 | 30 | // sha256 is default 31 | $sha256 = $fs->hash('file.txt'); 32 | $sha256 = $fs->hash('file.txt', 'sha256'); 33 | $md5 = $fs->hash('file.txt', 'md5'); 34 | $sha1 = $fs->hash('file.txt', 'sha1'); 35 | ``` 36 | 37 | ## License 38 | 39 | flysystem-hash is licensed under the [MIT License](http://opensource.org/licenses/MIT). 40 | 41 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "emgag/flysystem-hash", 3 | "description": "Flysystem plugin for generating a hash value of a given file", 4 | "keywords": [ 5 | "flysystem", 6 | "hash", 7 | "sha1", 8 | "sha256", 9 | "md5" 10 | ], 11 | "homepage": "https://github.com/emgag/flysystem-hash", 12 | "type": "library", 13 | "authors": [ 14 | { 15 | "name": "Matthias Blaser", 16 | "email": "git@mooch.ch" 17 | } 18 | ], 19 | "license": "MIT", 20 | "require": { 21 | "php": "^7.3 || ^8.0", 22 | "league/flysystem": "^1.0" 23 | }, 24 | "require-dev": { 25 | "league/flysystem-webdav": "^1.0", 26 | "phpunit/phpunit": "^9" 27 | }, 28 | "autoload": { 29 | "psr-4": { 30 | "Emgag\\Flysystem\\Hash\\": "src/" 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /phpunit.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ./src/ 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | ./tests/ 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/HashPlugin.php: -------------------------------------------------------------------------------- 1 | filesystem->readStream($path); 36 | 37 | if ($stream === false) { 38 | return false; 39 | } 40 | 41 | $hc = hash_init($algo); 42 | hash_update_stream($hc, $stream); 43 | 44 | return hash_final($hc); 45 | } 46 | 47 | } -------------------------------------------------------------------------------- /tests/HashPluginTest.php: -------------------------------------------------------------------------------- 1 | fs = new Filesystem(new Local(__DIR__ . '/files')); 31 | $this->plugin = new HashPlugin; 32 | $this->fs->addPlugin($this->plugin); 33 | 34 | // make sure test file3.txt is not readable 35 | chmod(__DIR__ . '/files/file3.txt', 0); 36 | } 37 | 38 | /** 39 | * Test plugin methods directly 40 | */ 41 | public function testPlugin() 42 | { 43 | self::assertEquals('hash', $this->plugin->getMethod()); 44 | } 45 | 46 | /** 47 | * Check correct hash values 48 | * 49 | * @param $file 50 | * @param $algo 51 | * @param $expect 52 | * @dataProvider providerHashes 53 | */ 54 | public function testHash($file, $algo, $expect) 55 | { 56 | if (function_exists('hash_equals')) { 57 | self::assertTrue(hash_equals($expect, $this->fs->hash($file, $algo))); 58 | } else { 59 | self::assertEquals($expect, $this->fs->hash($file, $algo)); 60 | } 61 | } 62 | 63 | /** 64 | * Check if default hash algo is sha256 as promised 65 | */ 66 | public function testDefaultHash() 67 | { 68 | self::assertEquals( 69 | $this->fs->hash('file1.txt'), 70 | $this->fs->hash('file1.txt', 'sha256') 71 | ); 72 | } 73 | 74 | public function testUnsupportedAlgo() 75 | { 76 | $this->expectException(\InvalidArgumentException::class); 77 | $this->fs->hash('file1.txt', 'supersecretnsaalgorithm'); 78 | } 79 | 80 | public function testFileNotFound() 81 | { 82 | $this->expectException(FileNotFoundException::class); 83 | $this->fs->hash('filenotfound'); 84 | } 85 | 86 | /** 87 | * Test unreadable file 88 | */ 89 | public function testUnreadableFile() 90 | { 91 | self::assertFalse(@$this->fs->hash('file3.txt')); 92 | } 93 | 94 | /** 95 | * @return array 96 | */ 97 | public function providerHashes() 98 | { 99 | return [ 100 | ['file1.txt', 'sha256', 'c147efcfc2d7ea666a9e4f5187b115c90903f0fc896a56df9a6ef5d8f3fc9f31'], 101 | ['file2.txt', 'sha256', '3377870dfeaaa7adf79a374d2702a3fdb13e5e5ea0dd8aa95a802ad39044a92f'], 102 | ['file1.txt', 'sha1', '60b27f004e454aca81b0480209cce5081ec52390'], 103 | ['file2.txt', 'sha1', 'cb99b709a1978bd205ab9dfd4c5aaa1fc91c7523'], 104 | ['file1.txt', 'md5', '826e8142e6baabe8af779f5f490cf5f5'], 105 | ['file2.txt', 'md5', '1c1c96fd2cf8330db0bfa936ce82f3b9'] 106 | ]; 107 | } 108 | 109 | 110 | } 111 | -------------------------------------------------------------------------------- /tests/files/file1.txt: -------------------------------------------------------------------------------- 1 | file1 -------------------------------------------------------------------------------- /tests/files/file2.txt: -------------------------------------------------------------------------------- 1 | file2 -------------------------------------------------------------------------------- /tests/files/file3.txt: -------------------------------------------------------------------------------- 1 | file3 2 | --------------------------------------------------------------------------------