Skip to content

Commit cb0ba07

Browse files
authored
store new hash for integrity check (#47)
Signed-off-by: rahul <[email protected]>
1 parent 26ff238 commit cb0ba07

File tree

3 files changed

+92
-29
lines changed

3 files changed

+92
-29
lines changed

src/FileHashChecker.php

Lines changed: 68 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,53 +2,55 @@
22

33
namespace Rcsofttech85\FileHandler;
44

5+
use Rcsofttech85\FileHandler\Exception\FileHandlerException;
56
use Rcsofttech85\FileHandler\Exception\HashException;
67
use Rcsofttech85\FileHandler\Validator\FileValidatorTrait;
78

89
class FileHashChecker
910
{
1011
use FileValidatorTrait;
1112

13+
1214
public const ALGO_256 = 'sha3-256';
1315
public const ALGO_512 = 'sha3-512';
1416

17+
private const SEARCH_COLUMN_NAME = 'File';
18+
private const SEARCH_COLUMN_VALUE = 'Hash';
19+
20+
1521
/**
16-
* @param string $filename
1722
* @param CsvFileHandler $csvFileHandler
18-
* @throws Exception\FileHandlerException
1923
*/
20-
public function __construct(private string $filename, private readonly CsvFileHandler $csvFileHandler)
24+
public function __construct(private readonly CsvFileHandler $csvFileHandler)
2125
{
22-
$this->filename = $this->validateFileName($filename);
2326
}
2427

2528
/**
26-
* @param string $storedHashesFile
29+
* @param string $filename
2730
* @param string $algo
2831
* @return bool
29-
* @throws Exception\FileHandlerException
32+
* @throws FileHandlerException
3033
* @throws HashException
3134
*/
3235

33-
public function verifyHash(string $storedHashesFile, string $algo = self::ALGO_256): bool
36+
public function verifyHash(string $filename, string $algo = self::ALGO_256): bool
3437
{
35-
if (!$storedHashesFile) {
36-
throw new HashException('file not found');
37-
}
38-
38+
$storedHashesFile = $this->getParameter(self::STORED_HASH_FILE);
3939
$file = $this->csvFileHandler->searchInCsvFile(
4040
filename: $storedHashesFile,
41-
keyword: $this->filename,
42-
column: 'File',
41+
keyword: $filename,
42+
column: self::SEARCH_COLUMN_NAME,
4343
format: FileHandler::ARRAY_FORMAT
4444
);
4545

46+
4647
if (!$file || !is_array($file)) {
4748
throw new HashException('this file is not hashed');
4849
}
4950

5051
$expectedHash = $file['Hash'];
51-
$hash = $this->hashFile($algo);
52+
$hash = $this->hashFile($filename, $algo);
53+
5254

5355
if ($hash !== $expectedHash) {
5456
return false;
@@ -58,16 +60,65 @@ public function verifyHash(string $storedHashesFile, string $algo = self::ALGO_2
5860
}
5961

6062
/**
63+
* @param string $filename
6164
* @param string $algo
6265
* @return string
63-
* @throws HashException
66+
* @throws HashException|FileHandlerException
6467
*/
6568

66-
public function hashFile(string $algo = self::ALGO_256): string
69+
public function hashFile(string $filename, string $algo = self::ALGO_256): string
6770
{
71+
$this->validateFileName($filename);
6872
if (!in_array($algo, [self::ALGO_512, self::ALGO_256])) {
6973
throw new HashException('algorithm not supported');
7074
}
71-
return hash_file($algo, $this->filename);
75+
76+
if (!$hash = hash_file($algo, $filename)) {
77+
throw new HashException('could not hash file');
78+
}
79+
80+
$storedHashesFile = $this->getParameter(self::STORED_HASH_FILE);
81+
82+
83+
$file = fopen($storedHashesFile, 'a+');
84+
if (!$file) {
85+
throw new FileHandlerException('file not found');
86+
}
87+
$this->checkHeaderExists($file);
88+
89+
90+
try {
91+
$filenameExists = $this->csvFileHandler->searchInCsvFile(
92+
filename: $storedHashesFile,
93+
keyword: $filename,
94+
column: 'File'
95+
);
96+
97+
if (!$filenameExists) {
98+
fputcsv($file, [$filename, $hash]);
99+
}
100+
} catch (FileHandlerException) {
101+
fputcsv($file, [$filename, $hash]);
102+
} finally {
103+
fclose($file);
104+
}
105+
106+
107+
return $hash;
108+
}
109+
110+
/**
111+
* @param mixed $storedHashFile
112+
* @return void
113+
*/
114+
private function checkHeaderExists(mixed $storedHashFile): void
115+
{
116+
$header = fgetcsv($storedHashFile);
117+
118+
if (!$header || $header[0] !== self::SEARCH_COLUMN_NAME || $header[1] !== self::SEARCH_COLUMN_VALUE) {
119+
fseek($storedHashFile, 0);
120+
fputcsv($storedHashFile, [self::SEARCH_COLUMN_NAME, self::SEARCH_COLUMN_VALUE]);
121+
fflush($storedHashFile);
122+
}
72123
}
73124
}

src/config/services.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
parameters:
22
filename: 'movie.csv'
33
secret: 'password'
4-
hash_file_name: 'test'
4+
55

66

77

@@ -22,7 +22,7 @@ services:
2222

2323
file_hash:
2424
class: 'Rcsofttech85\FileHandler\FileHashChecker'
25-
arguments: [ '%filename%','@csv_file_handler' ]
25+
arguments: [ '@csv_file_handler' ]
2626

2727
json_file_handler:
2828
class: 'Rcsofttech85\FileHandler\JsonFileHandler'

tests/unit/FileHashCheckerTest.php

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
class FileHashCheckerTest extends BaseTest
1212
{
13-
private static string $file;
1413
private FileHashChecker|null $fileHash = null;
1514

1615

@@ -31,30 +30,27 @@ public static function setUpBeforeClass(): void
3130
{
3231
parent::setUpBeforeClass();
3332

34-
$file = self::$containerBuilder->getParameter('STORED_HASH_FILE');
35-
if (is_string($file)) {
36-
self::$file = $file;
37-
}
3833
static::$files[] = 'sample';
3934
}
4035

4136

4237
/**
4338
* @throws HashException
39+
* @throws FileHandlerException
4440
*/
4541
#[Test]
4642
public function shouldGenerateValidHashForDifferentAlgo(): void
4743
{
4844
$expectedHash = "5923032f7e18edf69e1a3221be3205ce658ec0e4fb274016212a09a804240683";
4945

50-
$actualHash = $this->fileHash->hashFile(); //default ALGO_256
46+
$actualHash = $this->fileHash->hashFile(filename: 'movie.csv'); //default ALGO_256
5147

5248
$this->assertEquals($expectedHash, $actualHash);
5349

5450
$expectedHash = "1050bcc2d7d840d634f067a22abb4cd693b1f2590849982e29a6f9bb28963f733" .
5551
"92b63ea24ae17edfaa500ee62b9e5482b9648af0b2b7d941992af3b0f9cbd3b";
5652

57-
$actualHash = $this->fileHash->hashFile(FileHashChecker::ALGO_512);
53+
$actualHash = $this->fileHash->hashFile(filename: 'movie.csv', algo: FileHashChecker::ALGO_512);
5854

5955
$this->assertEquals($expectedHash, $actualHash);
6056
}
@@ -66,7 +62,7 @@ public function shouldGenerateValidHashForDifferentAlgo(): void
6662
#[Test]
6763
public function checkFileIntegrityReturnsTrueIfHashMatch(): void
6864
{
69-
$isVerified = $this->fileHash->verifyHash(storedHashesFile: self::$file);
65+
$isVerified = $this->fileHash->verifyHash(filename: 'movie.csv');
7066

7167
$this->assertTrue($isVerified);
7268
}
@@ -81,7 +77,7 @@ public function shouldReturnFalseIfFileIsModified(): void
8177
$backup = file_get_contents("movie.csv");
8278
file_put_contents("movie.csv", "modified", FILE_APPEND);
8379

84-
$isVerified = $this->fileHash->verifyHash(self::$file);
80+
$isVerified = $this->fileHash->verifyHash('movie.csv');
8581

8682
$this->assertfalse($isVerified);
8783

@@ -95,8 +91,24 @@ public function shouldReturnFalseIfFileIsModified(): void
9591
#[Test]
9692
public function shouldReturnFalseIfDifferentAlgoIsUsedForVerifyHash(): void
9793
{
98-
$isVerified = $this->fileHash->verifyHash(self::$file, FileHashChecker::ALGO_512);
94+
$isVerified = $this->fileHash->verifyHash('movie.csv', FileHashChecker::ALGO_512);
9995

10096
$this->assertFalse($isVerified);
10197
}
98+
99+
/**
100+
* @throws HashException
101+
* @throws FileHandlerException
102+
*/
103+
#[Test]
104+
public function shouldAddRecordIfNewFileIsHashed(): void
105+
{
106+
file_put_contents('sample', "hello");
107+
108+
$this->fileHash->hashFile('sample', FileHashChecker::ALGO_512);
109+
110+
$isVerified = $this->fileHash->verifyHash('sample', FileHashChecker::ALGO_512);
111+
112+
$this->assertTrue($isVerified);
113+
}
102114
}

0 commit comments

Comments
 (0)