Completed
Push — master ( ab2a6d...da3f44 )
by Tony Karavasilev (Тони
08:35
created

AbstractKeyedHashFunction::hashFile()   B

Complexity

Conditions 10
Paths 26

Size

Total Lines 51
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 24
CRAP Score 10

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 27
c 1
b 0
f 0
dl 0
loc 51
ccs 24
cts 24
cp 1
rs 7.6666
cc 10
nc 26
nop 1
crap 10

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * Abstraction for keyed hash objects like HMAC functions (keyed-hash message authentication code hash).
5
 */
6
7
namespace CryptoManana\Core\Abstractions\MessageDigestion;
8
9
use \CryptoManana\Core\Abstractions\MessageDigestion\AbstractHashAlgorithm as HashAlgorithm;
10
use \CryptoManana\Core\Interfaces\MessageDigestion\DigestionKeyInterface as KeyedHashing;
11
use \CryptoManana\Core\Interfaces\MessageDigestion\ObjectHashingInterface as ObjectHashing;
12
use \CryptoManana\Core\Interfaces\MessageDigestion\FileHashingInterface as FileHashing;
13
use \CryptoManana\Core\Traits\MessageDigestion\DigestionKeyTrait as DigestionKey;
14
use \CryptoManana\Core\Traits\MessageDigestion\ObjectHashingTrait as HashObjects;
15
use \CryptoManana\Core\StringBuilder as StringBuilder;
16
17
/**
18
 * Class AbstractKeyedHashFunction - Abstraction for keyed hash classes.
19
 *
20
 * @package CryptoManana\Core\Abstractions\MessageDigestion
21
 *
22
 * @mixin DigestionKey
23
 * @mixin HashObjects
24
 */
25
abstract class AbstractKeyedHashFunction extends HashAlgorithm implements KeyedHashing, ObjectHashing, FileHashing
26
{
27
    /**
28
     * Data salting capabilities.
29
     *
30
     * {@internal Reusable implementation of `DigestionKeyInterface`. }}
31
     */
32
    use DigestionKey;
33
34
    /**
35
     * Object hashing capabilities.
36
     *
37
     * {@internal Reusable implementation of `ObjectHashingInterface`. }}
38
     */
39
    use HashObjects;
40
41
    /**
42
     * The internal name of the algorithm.
43
     */
44
    const ALGORITHM_NAME = 'none';
45
46
    /**
47
     * Flag to force native code polyfill realizations, if available.
48
     *
49
     * @var bool Flag to force native realizations.
50
     */
51
    protected $useNative = false;
52
53
    /**
54
     * The key string property storage.
55
     *
56
     * @var string The digestion key string value.
57
     */
58
    protected $key = '';
59
60
    /**
61
     * Internal method for location and filename validation.
62
     *
63
     * @param string $filename The filename and location.
64
     *
65
     * @throws \Exception Validation errors.
66
     */
67 44
    protected function validateFileNamePath($filename)
68
    {
69 44
        $filename = StringBuilder::stringReplace("\0", '', $filename); // (ASCII 0 (0x00))
70 44
        $filename = realpath($filename); // Path traversal escape and absolute path fetching
71
72
        // Clear path cache
73 44
        if (!empty($filename)) {
74 22
            clearstatcache(true, $filename);
75
        }
76
77
        // Check if path is valid and the file is readable
78 44
        if ($filename === false || !file_exists($filename) || !is_readable($filename) || !is_file($filename)) {
79 22
            throw new \RuntimeException('File is not found or can not be accessed.');
80
        }
81 22
    }
82
83
    /**
84
     * Unkeyed hash algorithm constructor.
85
     */
86 396
    public function __construct()
87
    {
88 396
    }
89
90
    /**
91
     * Calculates a hash value for the given data.
92
     *
93
     * @param string $data The input string.
94
     *
95
     * @return string The digest.
96
     * @throws \Exception Validation errors.
97
     */
98 140
    public function hashData($data)
99
    {
100 140
        if (!is_string($data)) {
101 14
            throw new \InvalidArgumentException('The data for hashing must be a string or a binary string.');
102
        }
103
104 126
        $data = $this->addSaltString($data);
105
106 126
        $digest = hash_hmac(
107 126
            static::ALGORITHM_NAME,
108
            $data,
109 126
            $this->key,
110 126
            ($this->digestFormat === self::DIGEST_OUTPUT_RAW)
111
        );
112
113 126
        $digest = $this->changeOutputFormat($digest);
114
115 126
        return $digest;
116
    }
117
118
    /**
119
     * Calculates a hash value for the content of the given filename and location.
120
     *
121
     * @param string $filename The full path and name of the file for hashing.
122
     *
123
     * @return string The digest.
124
     * @throws \Exception Validation errors.
125
     */
126 66
    public function hashFile($filename)
127
    {
128
        // Validate input type
129 66
        if (!is_string($filename)) {
130 22
            throw new \InvalidArgumentException('The file path must be of type string.');
131
        }
132
133 44
        $this->validateFileNamePath($filename);
134
135
        $useFileSalting = (
136
            (
137
                // If there is an non-empty salt string set and salting is enabled
138 22
                $this->salt !== '' &&
139 22
                $this->saltingMode !== self::SALTING_MODE_NONE
140
            ) || (
141
                // If there is an empty salt string set and the salting mode duplicates/manipulates the input
142 22
                $this->salt === '' &&
143 22
                in_array($this->saltingMode, [self::SALTING_MODE_INFIX_SALT, self::SALTING_MODE_PALINDROME_MIRRORING])
144
            )
145
        );
146
147 22
        if ($this->useNative || $useFileSalting) {
148
            /**
149
             * {@internal An optimization for native performance that spears string manipulations and function calls. }}
150
             */
151 22
            if (!$useFileSalting) {
152 22
                $oldSalt = $this->salt;
153 22
                $oldMode = $this->saltingMode;
154
155 22
                $this->salt = '';
156 22
                $this->saltingMode = self::SALTING_MODE_NONE;
157
            }
158
159 22
            $digest = $this->hashData(file_get_contents($filename));
160
161 22
            if (!$useFileSalting && isset($oldSalt, $oldMode)) {
162 22
                $this->salt = $oldSalt;
163 22
                $this->saltingMode = $oldMode;
164
            }
165
        } else {
166 22
            $digest = hash_hmac_file(
167 22
                static::ALGORITHM_NAME,
168
                $filename,
169 22
                $this->key,
170 22
                ($this->digestFormat === self::DIGEST_OUTPUT_RAW)
171
            );
172
173 22
            $digest = $this->changeOutputFormat($digest);
174
        }
175
176 22
        return $digest;
177
    }
178
179
    /**
180
     * Get debug information for the class instance.
181
     *
182
     * @return array Debug information.
183
     */
184 22
    public function __debugInfo()
185
    {
186
        return [
187 22
            'standard' => static::ALGORITHM_NAME,
188 22
            'type' => 'keyed digestion or HMAC',
189 22
            'key' => $this->key,
190 22
            'salt' => $this->salt,
191 22
            'mode' => $this->saltingMode,
192
        ];
193
    }
194
}
195