Passed
Push — master ( bf05ce...067897 )
by Tony Karavasilev (Тони
07:17
created

AbstractUnkeyedHashFunction   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 135
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 15
eloc 39
c 2
b 0
f 0
dl 0
loc 135
ccs 41
cts 41
cp 1
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A hashFile() 0 22 2
A hashObject() 0 9 2
B validateFileNamePath() 0 18 7
A hashData() 0 13 2
A __debugInfo() 0 7 1
A __construct() 0 2 1
1
<?php
2
3
/**
4
 * Abstraction for unkeyed hash objects like checksums and plain cryptographic hash functions.
5
 */
6
7
namespace CryptoManana\Core\Abstractions\MessageDigestion;
8
9
use \CryptoManana\Core\Abstractions\MessageDigestion\AbstractHashAlgorithm as HashAlgorithm;
10
use \CryptoManana\Core\Interfaces\MessageDigestion\ObjectHashingInterface as ObjectHashing;
11
use \CryptoManana\Core\Interfaces\MessageDigestion\FileHashingInterface as FileHashing;
12
13
/**
14
 * Class AbstractUnkeyedHashFunction - Abstraction for unkeyed hash classes.
15
 *
16
 * @package CryptoManana\Core\Abstractions\MessageDigestion
17
 */
18
abstract class AbstractUnkeyedHashFunction extends HashAlgorithm implements ObjectHashing, FileHashing
19
{
20
    /**
21
     * The internal name of the algorithm.
22
     */
23
    const ALGORITHM_NAME = 'none';
24
25
    /**
26
     * Flag to force native code polyfill realizations, if available.
27
     *
28
     * @var bool Flag to force native realizations.
29
     */
30
    protected $useNative = false;
31
32
    /**
33
     * Internal method for location and filename validation.
34
     *
35
     * @param string $filename The filename and location.
36
     *
37
     * @throws \Exception Validation errors.
38
     */
39 66
    protected function validateFileNamePath($filename)
40
    {
41
        // Validate input type
42 66
        if (!is_string($filename)) {
43 22
            throw new \InvalidArgumentException('The file path must be of type string.');
44
        }
45
46 44
        $filename = str_replace("\0", '', $filename); // (ASCII 0 (0x00))
47 44
        $filename = realpath($filename); // Path traversal escape and absolute path fetching
48
49
        // Clear path cache
50 44
        if (!empty($filename)) {
51 22
            clearstatcache(true, $filename);
52
        }
53
54
        // Check if path is valid and the file is readable
55 44
        if ($filename === false || !file_exists($filename) || !is_readable($filename) || !is_file($filename)) {
56 22
            throw new \RuntimeException('File is not found or can not be accessed.');
57
        }
58 22
    }
59
60
    /**
61
     * Unkeyed hash algorithm constructor.
62
     */
63 352
    public function __construct()
64
    {
65 352
    }
66
67
    /**
68
     * Calculates a hash value for the given data.
69
     *
70
     * @param string $data The input string.
71
     *
72
     * @return string The digest.
73
     * @throws \Exception Validation errors.
74
     */
75 126
    public function hashData($data)
76
    {
77 126
        if (!is_string($data)) {
78 14
            throw new \InvalidArgumentException('The data for hashing must be a string or a binary string.');
79
        }
80
81 112
        $data = $this->addSaltString($data);
82
83 112
        $digest = hash(static::ALGORITHM_NAME, $data, ($this->digestFormat === self::DIGEST_OUTPUT_RAW));
84
85 112
        $digest = $this->changeOutputFormat($digest);
86
87 112
        return $digest;
88
    }
89
90
    /**
91
     * Calculates a hash value for the content of the given filename and location.
92
     *
93
     * @param string $filename The full path and name of the file for hashing.
94
     *
95
     * @return string The digest.
96
     * @throws \Exception Validation errors.
97
     */
98 66
    public function hashFile($filename)
99
    {
100 66
        $this->validateFileNamePath($filename);
101
102 22
        if ($this->useNative) {
103 22
            $data = file_get_contents($filename);
104
105 22
            $oldSalt = $this->getSalt();
106 22
            $oldMode = $this->getSaltingMode();
107
108 22
            $this->setSalt('')->setSaltingMode(self::SALTING_MODE_NONE);
109
110 22
            $digest = $this->hashData($data);
111
112 22
            $this->setSalt($oldSalt)->setSaltingMode($oldMode);
113
        } else {
114 22
            $digest = hash_file(static::ALGORITHM_NAME, $filename, ($this->digestFormat === self::DIGEST_OUTPUT_RAW));
115
116 22
            $digest = $this->changeOutputFormat($digest);
117
        }
118
119 22
        return $digest;
120
    }
121
122
    /**
123
     * Calculates a hash value for the serialized value of the given object.
124
     *
125
     * @param object|\stdClass $object The full path and name of the file for hashing.
126
     *
127
     * @return string The digest.
128
     * @throws \Exception Validation errors.
129
     */
130 44
    public function hashObject($object)
131
    {
132 44
        if (is_object($object)) {
133 22
            $object = serialize($object);
134
        } else {
135 22
            throw new \InvalidArgumentException('The data for hashing must be an object instance.');
136
        }
137
138 22
        return $this->hashData($object);
139
    }
140
141
    /**
142
     * Get debug information for the class instance.
143
     *
144
     * @return array Debug information.
145
     */
146 22
    public function __debugInfo()
147
    {
148
        return [
149 22
            'standard' => static::ALGORITHM_NAME,
150 22
            'type' => 'unkeyed digestion or checksum',
151 22
            'salt' => $this->salt,
152 22
            'mode' => $this->saltingMode,
153
        ];
154
    }
155
}
156