Completed
Push — master ( 6cf230...526008 )
by Tony Karavasilev (Тони
06:39
created

AbstractUnkeyedHashFunction::hashObject()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 5
c 1
b 0
f 0
dl 0
loc 9
ccs 5
cts 5
cp 1
rs 10
cc 2
nc 2
nop 1
crap 2
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 44
    protected function validateFileNamePath($filename)
40
    {
41 44
        $filename = str_replace("\0", '', $filename); // (ASCII 0 (0x00))
42 44
        $filename = realpath($filename); // Path traversal escape and absolute path fetching
43
44
        // Clear path cache
45 44
        if (!empty($filename)) {
46 22
            clearstatcache(true, $filename);
47
        }
48
49
        // Check if path is valid and the file is readable
50 44
        if ($filename === false || !file_exists($filename) || !is_readable($filename) || !is_file($filename)) {
51 22
            throw new \RuntimeException('File is not found or can not be accessed.');
52
        }
53 22
    }
54
55
    /**
56
     * Unkeyed hash algorithm constructor.
57
     */
58 352
    public function __construct()
59
    {
60 352
    }
61
62
    /**
63
     * Calculates a hash value for the given data.
64
     *
65
     * @param string $data The input string.
66
     *
67
     * @return string The digest.
68
     * @throws \Exception Validation errors.
69
     */
70 126
    public function hashData($data)
71
    {
72 126
        if (!is_string($data)) {
73 14
            throw new \InvalidArgumentException('The data for hashing must be a string or a binary string.');
74
        }
75
76 112
        $data = $this->addSaltString($data);
77
78 112
        $digest = hash(static::ALGORITHM_NAME, $data, ($this->digestFormat === self::DIGEST_OUTPUT_RAW));
79
80 112
        $digest = $this->changeOutputFormat($digest);
81
82 112
        return $digest;
83
    }
84
85
    /**
86
     * Calculates a hash value for the content of the given filename and location.
87
     *
88
     * @param string $filename The full path and name of the file for hashing.
89
     *
90
     * @return string The digest.
91
     * @throws \Exception Validation errors.
92
     */
93 66
    public function hashFile($filename)
94
    {
95
        // Validate input type
96 66
        if (!is_string($filename)) {
97 22
            throw new \InvalidArgumentException('The file path must be of type string.');
98
        }
99
100 44
        $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