Protection   F
last analyzed

Complexity

Total Complexity 68

Size/Duplication

Total Lines 464
Duplicated Lines 0 %

Test Coverage

Coverage 99.31%

Importance

Changes 0
Metric Value
wmc 68
eloc 127
dl 0
loc 464
ccs 143
cts 144
cp 0.9931
rs 2.96
c 0
b 0
f 0

48 Methods

Rating   Name   Duplication   Size   Complexity  
A getSheet() 0 3 1
A getSalt() 0 3 1
A setSheet() 0 5 1
A getAlgorithm() 0 3 1
A setPassword() 0 11 2
A setFormatCells() 0 5 1
A __construct() 0 2 1
A setFormatRows() 0 5 1
A setDeleteColumns() 0 5 1
A getSpinCount() 0 3 1
A setPivotTables() 0 5 1
A setInsertRows() 0 5 1
A getSelectLockedCells() 0 3 1
A setAlgorithmName() 0 5 1
A getFormatRows() 0 3 1
A verify() 0 9 2
A setSelectUnlockedCells() 0 5 1
A setSort() 0 5 1
A setSpinCount() 0 5 1
A setAutoFilter() 0 5 1
A setDeleteRows() 0 5 1
A getInsertRows() 0 3 1
A getScenarios() 0 3 1
A getSort() 0 3 1
A setSelectLockedCells() 0 5 1
A setInsertColumns() 0 5 1
A generateSalt() 0 3 1
A setFormatColumns() 0 5 1
A getAutoFilter() 0 3 1
A setObjects() 0 5 1
A getPivotTables() 0 3 1
A setInsertHyperlinks() 0 5 1
A getSelectUnlockedCells() 0 3 1
A setScenarios() 0 5 1
A getFormatCells() 0 3 1
A setAlgorithm() 0 3 1
A setSaltValue() 0 5 1
A getDeleteColumns() 0 3 1
A getDeleteRows() 0 3 1
A getObjects() 0 3 1
A __clone() 0 8 3
A getPassword() 0 3 1
A getFormatColumns() 0 3 1
C isProtectionEnabled() 0 20 17
A getInsertHyperlinks() 0 3 1
A setHashValue() 0 3 1
A setSalt() 0 3 1
A getInsertColumns() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like Protection often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Protection, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Worksheet;
4
5
use PhpOffice\PhpSpreadsheet\Shared\PasswordHasher;
6
7
class Protection
8
{
9
    const ALGORITHM_MD2 = 'MD2';
10
    const ALGORITHM_MD4 = 'MD4';
11
    const ALGORITHM_MD5 = 'MD5';
12
    const ALGORITHM_SHA_1 = 'SHA-1';
13
    const ALGORITHM_SHA_256 = 'SHA-256';
14
    const ALGORITHM_SHA_384 = 'SHA-384';
15
    const ALGORITHM_SHA_512 = 'SHA-512';
16
    const ALGORITHM_RIPEMD_128 = 'RIPEMD-128';
17
    const ALGORITHM_RIPEMD_160 = 'RIPEMD-160';
18
    const ALGORITHM_WHIRLPOOL = 'WHIRLPOOL';
19
20
    /**
21
     * Autofilters are locked when sheet is protected, default true.
22
     */
23
    private ?bool $autoFilter = null;
24
25
    /**
26
     * Deleting columns is locked when sheet is protected, default true.
27
     */
28
    private ?bool $deleteColumns = null;
29
30
    /**
31
     * Deleting rows is locked when sheet is protected, default true.
32
     */
33
    private ?bool $deleteRows = null;
34
35
    /**
36
     * Formatting cells is locked when sheet is protected, default true.
37
     */
38
    private ?bool $formatCells = null;
39
40
    /**
41
     * Formatting columns is locked when sheet is protected, default true.
42
     */
43
    private ?bool $formatColumns = null;
44
45
    /**
46
     * Formatting rows is locked when sheet is protected, default true.
47
     */
48
    private ?bool $formatRows = null;
49
50
    /**
51
     * Inserting columns is locked when sheet is protected, default true.
52
     */
53
    private ?bool $insertColumns = null;
54
55
    /**
56
     * Inserting hyperlinks is locked when sheet is protected, default true.
57
     */
58
    private ?bool $insertHyperlinks = null;
59
60
    /**
61
     * Inserting rows is locked when sheet is protected, default true.
62
     */
63
    private ?bool $insertRows = null;
64
65
    /**
66
     * Objects are locked when sheet is protected, default false.
67
     */
68
    private ?bool $objects = null;
69
70
    /**
71
     * Pivot tables are locked when the sheet is protected, default true.
72
     */
73
    private ?bool $pivotTables = null;
74
75
    /**
76
     * Scenarios are locked when sheet is protected, default false.
77
     */
78
    private ?bool $scenarios = null;
79
80
    /**
81
     * Selection of locked cells is locked when sheet is protected, default false.
82
     */
83
    private ?bool $selectLockedCells = null;
84
85
    /**
86
     * Selection of unlocked cells is locked when sheet is protected, default false.
87
     */
88
    private ?bool $selectUnlockedCells = null;
89
90
    /**
91
     * Sheet is locked when sheet is protected, default false.
92
     */
93
    private ?bool $sheet = null;
94
95
    /**
96
     * Sorting is locked when sheet is protected, default true.
97
     */
98
    private ?bool $sort = null;
99
100
    /**
101
     * Hashed password.
102
     */
103
    private string $password = '';
104
105
    /**
106
     * Algorithm name.
107
     */
108
    private string $algorithm = '';
109
110
    /**
111
     * Salt value.
112
     */
113
    private string $salt = '';
114
115
    /**
116
     * Spin count.
117
     */
118
    private int $spinCount = 10000;
119
120
    /**
121
     * Create a new Protection.
122
     */
123 10014
    public function __construct()
124
    {
125 10014
    }
126
127
    /**
128
     * Is some sort of protection enabled?
129
     */
130 9057
    public function isProtectionEnabled(): bool
131
    {
132 9057
        return
133 9057
            $this->password !== ''
134 9057
            || isset($this->sheet)
135 9057
            || isset($this->objects)
136 9057
            || isset($this->scenarios)
137 9057
            || isset($this->formatCells)
138 9057
            || isset($this->formatColumns)
139 9057
            || isset($this->formatRows)
140 9057
            || isset($this->insertColumns)
141 9057
            || isset($this->insertRows)
142 9057
            || isset($this->insertHyperlinks)
143 9057
            || isset($this->deleteColumns)
144 9057
            || isset($this->deleteRows)
145 9057
            || isset($this->selectLockedCells)
146 9057
            || isset($this->sort)
147 9057
            || isset($this->autoFilter)
148 9057
            || isset($this->pivotTables)
149 9057
            || isset($this->selectUnlockedCells);
150
    }
151
152 127
    public function getSheet(): ?bool
153
    {
154 127
        return $this->sheet;
155
    }
156
157 47
    public function setSheet(?bool $sheet): self
158
    {
159 47
        $this->sheet = $sheet;
160
161 47
        return $this;
162
    }
163
164 121
    public function getObjects(): ?bool
165
    {
166 121
        return $this->objects;
167
    }
168
169 99
    public function setObjects(?bool $objects): self
170
    {
171 99
        $this->objects = $objects;
172
173 99
        return $this;
174
    }
175
176 121
    public function getScenarios(): ?bool
177
    {
178 121
        return $this->scenarios;
179
    }
180
181 97
    public function setScenarios(?bool $scenarios): self
182
    {
183 97
        $this->scenarios = $scenarios;
184
185 97
        return $this;
186
    }
187
188 121
    public function getFormatCells(): ?bool
189
    {
190 121
        return $this->formatCells;
191
    }
192
193 140
    public function setFormatCells(?bool $formatCells): self
194
    {
195 140
        $this->formatCells = $formatCells;
196
197 140
        return $this;
198
    }
199
200 121
    public function getFormatColumns(): ?bool
201
    {
202 121
        return $this->formatColumns;
203
    }
204
205 137
    public function setFormatColumns(?bool $formatColumns): self
206
    {
207 137
        $this->formatColumns = $formatColumns;
208
209 137
        return $this;
210
    }
211
212 121
    public function getFormatRows(): ?bool
213
    {
214 121
        return $this->formatRows;
215
    }
216
217 137
    public function setFormatRows(?bool $formatRows): self
218
    {
219 137
        $this->formatRows = $formatRows;
220
221 137
        return $this;
222
    }
223
224 121
    public function getInsertColumns(): ?bool
225
    {
226 121
        return $this->insertColumns;
227
    }
228
229 137
    public function setInsertColumns(?bool $insertColumns): self
230
    {
231 137
        $this->insertColumns = $insertColumns;
232
233 137
        return $this;
234
    }
235
236 121
    public function getInsertRows(): ?bool
237
    {
238 121
        return $this->insertRows;
239
    }
240
241 139
    public function setInsertRows(?bool $insertRows): self
242
    {
243 139
        $this->insertRows = $insertRows;
244
245 139
        return $this;
246
    }
247
248 121
    public function getInsertHyperlinks(): ?bool
249
    {
250 121
        return $this->insertHyperlinks;
251
    }
252
253 137
    public function setInsertHyperlinks(?bool $insertHyperLinks): self
254
    {
255 137
        $this->insertHyperlinks = $insertHyperLinks;
256
257 137
        return $this;
258
    }
259
260 121
    public function getDeleteColumns(): ?bool
261
    {
262 121
        return $this->deleteColumns;
263
    }
264
265 137
    public function setDeleteColumns(?bool $deleteColumns): self
266
    {
267 137
        $this->deleteColumns = $deleteColumns;
268
269 137
        return $this;
270
    }
271
272 121
    public function getDeleteRows(): ?bool
273
    {
274 121
        return $this->deleteRows;
275
    }
276
277 136
    public function setDeleteRows(?bool $deleteRows): self
278
    {
279 136
        $this->deleteRows = $deleteRows;
280
281 136
        return $this;
282
    }
283
284 121
    public function getSelectLockedCells(): ?bool
285
    {
286 121
        return $this->selectLockedCells;
287
    }
288
289 98
    public function setSelectLockedCells(?bool $selectLockedCells): self
290
    {
291 98
        $this->selectLockedCells = $selectLockedCells;
292
293 98
        return $this;
294
    }
295
296 121
    public function getSort(): ?bool
297
    {
298 121
        return $this->sort;
299
    }
300
301 140
    public function setSort(?bool $sort): self
302
    {
303 140
        $this->sort = $sort;
304
305 140
        return $this;
306
    }
307
308 121
    public function getAutoFilter(): ?bool
309
    {
310 121
        return $this->autoFilter;
311
    }
312
313 138
    public function setAutoFilter(?bool $autoFilter): self
314
    {
315 138
        $this->autoFilter = $autoFilter;
316
317 138
        return $this;
318
    }
319
320 121
    public function getPivotTables(): ?bool
321
    {
322 121
        return $this->pivotTables;
323
    }
324
325 136
    public function setPivotTables(?bool $pivotTables): self
326
    {
327 136
        $this->pivotTables = $pivotTables;
328
329 136
        return $this;
330
    }
331
332 121
    public function getSelectUnlockedCells(): ?bool
333
    {
334 121
        return $this->selectUnlockedCells;
335
    }
336
337 97
    public function setSelectUnlockedCells(?bool $selectUnlockedCells): self
338
    {
339 97
        $this->selectUnlockedCells = $selectUnlockedCells;
340
341 97
        return $this;
342
    }
343
344
    /**
345
     * Get hashed password.
346
     */
347 39
    public function getPassword(): string
348
    {
349 39
        return $this->password;
350
    }
351
352
    /**
353
     * Set Password.
354
     *
355
     * @param bool $alreadyHashed If the password has already been hashed, set this to true
356
     *
357
     * @return $this
358
     */
359 73
    public function setPassword(string $password, bool $alreadyHashed = false): static
360
    {
361 73
        if (!$alreadyHashed) {
362 12
            $salt = $this->generateSalt();
363 12
            $this->setSalt($salt);
364 12
            $password = PasswordHasher::hashPassword($password, $this->getAlgorithm(), $this->getSalt(), $this->getSpinCount());
365
        }
366
367 73
        $this->password = $password;
368
369 73
        return $this;
370
    }
371
372 2
    public function setHashValue(string $password): self
373
    {
374 2
        return $this->setPassword($password, true);
375
    }
376
377
    /**
378
     * Create a pseudorandom string.
379
     */
380 12
    private function generateSalt(): string
381
    {
382 12
        return base64_encode(random_bytes(16));
383
    }
384
385
    /**
386
     * Get algorithm name.
387
     */
388 39
    public function getAlgorithm(): string
389
    {
390 39
        return $this->algorithm;
391
    }
392
393
    /**
394
     * Set algorithm name.
395
     */
396 69
    public function setAlgorithm(string $algorithm): self
397
    {
398 69
        return $this->setAlgorithmName($algorithm);
399
    }
400
401
    /**
402
     * Set algorithm name.
403
     */
404 69
    public function setAlgorithmName(string $algorithm): self
405
    {
406 69
        $this->algorithm = $algorithm;
407
408 69
        return $this;
409
    }
410
411 13
    public function getSalt(): string
412
    {
413 13
        return $this->salt;
414
    }
415
416 13
    public function setSalt(string $salt): self
417
    {
418 13
        return $this->setSaltValue($salt);
419
    }
420
421 13
    public function setSaltValue(string $salt): self
422
    {
423 13
        $this->salt = $salt;
424
425 13
        return $this;
426
    }
427
428
    /**
429
     * Get spin count.
430
     */
431 14
    public function getSpinCount(): int
432
    {
433 14
        return $this->spinCount;
434
    }
435
436
    /**
437
     * Set spin count.
438
     */
439 3
    public function setSpinCount(int $spinCount): self
440
    {
441 3
        $this->spinCount = $spinCount;
442
443 3
        return $this;
444
    }
445
446
    /**
447
     * Verify that the given non-hashed password can "unlock" the protection.
448
     */
449 3
    public function verify(string $password): bool
450
    {
451 3
        if ($this->password === '') {
452 2
            return true;
453
        }
454
455 3
        $hash = PasswordHasher::hashPassword($password, $this->getAlgorithm(), $this->getSalt(), $this->getSpinCount());
456
457 3
        return $this->getPassword() === $hash;
458
    }
459
460
    /**
461
     * Implement PHP __clone to create a deep clone, not just a shallow copy.
462
     */
463 1
    public function __clone()
464
    {
465 1
        $vars = get_object_vars($this);
466 1
        foreach ($vars as $key => $value) {
467 1
            if (is_object($value)) {
468
                $this->$key = clone $value;
469
            } else {
470 1
                $this->$key = $value;
471
            }
472
        }
473
    }
474
}
475