Skip to content

Commit db3256f

Browse files
committed
PHP 8.1 fixes
1 parent 8c72161 commit db3256f

35 files changed

+451
-298
lines changed

composer.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
"php-coveralls/php-coveralls": "*",
2222
"squizlabs/php_codesniffer": "3.*"
2323
},
24+
"suggest": {
25+
"ext-gmp": "Required for optimized binomial calculations (also requires PHP >= 7.3)"
26+
},
2427
"autoload": {
2528
"psr-4": { "ZxcvbnPhp\\": "src/" }
2629
},

src/Feedback.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
<?php
22

3+
declare(strict_types=1);
4+
35
namespace ZxcvbnPhp;
46

57
use ZxcvbnPhp\Matchers\MatchInterface;

src/Matcher.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
<?php
22

3+
declare(strict_types=1);
4+
35
namespace ZxcvbnPhp;
46

57
use ZxcvbnPhp\Matchers\BaseMatch;

src/Matchers/BaseMatch.php

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
<?php
22

3+
declare(strict_types=1);
4+
35
namespace ZxcvbnPhp\Matchers;
46

7+
use JetBrains\PhpStorm\ArrayShape;
58
use ZxcvbnPhp\Scorer;
69

710
abstract class BaseMatch implements MatchInterface
@@ -45,13 +48,14 @@ public function __construct(string $password, int $begin, int $end, string $toke
4548
*
4649
* @param bool $isSoleMatch
4750
* Whether this is the only match in the password
48-
* @return array{warning: string, suggestions: array}
51+
* @return array
4952
* Associative array with warning (string) and suggestions (array of strings)
5053
*/
54+
#[ArrayShape(['warning' => 'string', 'suggestions' => 'string[]'])]
5155
abstract public function getFeedback(bool $isSoleMatch): array;
5256

5357
/**
54-
* Find all occurences of regular expression in a string.
58+
* Find all occurrences of regular expression in a string.
5559
*
5660
* @param string $string
5761
* String to search.
@@ -114,28 +118,48 @@ public static function findAll(string $string, string $regex, int $offset = 0):
114118
/**
115119
* Calculate binomial coefficient (n choose k).
116120
*
117-
* http://www.php.net/manual/en/ref.math.php#57895
118-
*
119-
* @param $n
120-
* @param $k
121+
* @param int $n
122+
* @param int $k
121123
* @return int
122124
*/
123125
public static function binom(int $n, int $k): int
124126
{
125-
$j = $res = 1;
127+
if (function_exists('gmp_binomial')) {
128+
return gmp_intval(gmp_binomial($n, $k));
129+
}
126130

127-
if ($k < 0 || $k > $n) {
128-
return 0;
131+
return self::binomPolyfill($n, $k);
132+
}
133+
134+
/**
135+
* Substitute for gmp_polynomial for non-negative values of n and k.
136+
* @param int $n
137+
* @param int $k
138+
* @return int
139+
*/
140+
public static function binomPolyfill(int $n, int $k): int
141+
{
142+
if ($k < 0 || $n < 0) {
143+
throw new \DomainException("n and k must be non-negative");
129144
}
130-
if (($n - $k) < $k) {
131-
$k = $n - $k;
145+
146+
if ($k > $n) {
147+
return 0;
132148
}
133-
while ($j <= $k) {
134-
$res *= $n--;
135-
$res /= $j++;
149+
150+
// $k and $n - $k will always produce the same value, so use smaller of the two
151+
$k = min($k, $n - $k);
152+
153+
$c = 1;
154+
155+
for ($i = 1; $i <= $k; $i++, $n--) {
156+
// We're aiming for $c * $n / $i, but the $c * $n part could overflow, so use $c / $i * $n instead. The caveat here is that in
157+
// order to get a precise answer, we need to avoid floats, which means we need to deal with whole part and the remainder
158+
// separately.
159+
$c = intdiv($c, $i) * $n + intdiv($c % $i * $n, $i);
136160
}
137161

138-
return $res;
162+
return $c;
139163
}
140164

141165
abstract protected function getRawGuesses(): float;

src/Matchers/Bruteforce.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
<?php
22

3+
declare(strict_types=1);
4+
35
namespace ZxcvbnPhp\Matchers;
46

7+
use JetBrains\PhpStorm\ArrayShape;
58
use ZxcvbnPhp\Scorer;
69

710
/**
@@ -30,6 +33,7 @@ public static function match(string $password, array $userInputs = []): array
3033
}
3134

3235

36+
#[ArrayShape(['warning' => 'string', 'suggestions' => 'string[]'])]
3337
public function getFeedback(bool $isSoleMatch): array
3438
{
3539
return [

src/Matchers/DateMatch.php

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
<?php
22

3+
declare(strict_types=1);
4+
35
namespace ZxcvbnPhp\Matchers;
46

7+
use JetBrains\PhpStorm\ArrayShape;
58
use ZxcvbnPhp\Matcher;
69

710
class DateMatch extends BaseMatch
@@ -105,6 +108,7 @@ public static function match(string $password, array $userInputs = []): array
105108
return $matches;
106109
}
107110

111+
#[ArrayShape(['warning' => 'string', 'suggestions' => 'string[]'])]
108112
public function getFeedback(bool $isSoleMatch): array
109113
{
110114
return [
@@ -202,9 +206,9 @@ protected static function datesWithoutSeparators(string $password): array
202206

203207
$possibleSplits = static::$DATE_SPLITS[mb_strlen($token)];
204208
foreach ($possibleSplits as $splitPositions) {
205-
$day = mb_substr($token, 0, $splitPositions[0]);
206-
$month = mb_substr($token, $splitPositions[0], $splitPositions[1] - $splitPositions[0]);
207-
$year = mb_substr($token, $splitPositions[1]);
209+
$day = (int)mb_substr($token, 0, $splitPositions[0]);
210+
$month = (int)mb_substr($token, $splitPositions[0], $splitPositions[1] - $splitPositions[0]);
211+
$year = (int)mb_substr($token, $splitPositions[1]);
208212

209213
$date = static::checkDate([$day, $month, $year]);
210214
if ($date !== false) {
@@ -285,21 +289,21 @@ protected static function checkDate(array $ints)
285289
return false;
286290
}
287291

288-
$invalidYear = count(array_filter($ints, function (int $int) {
292+
$invalidYear = count(array_filter($ints, function (int $int): bool {
289293
return ($int >= 100 && $int < static::MIN_YEAR)
290294
|| ($int > static::MAX_YEAR);
291295
}));
292296
if ($invalidYear > 0) {
293297
return false;
294298
}
295299

296-
$over12 = count(array_filter($ints, function (int $int) {
300+
$over12 = count(array_filter($ints, function (int $int): bool {
297301
return $int > 12;
298302
}));
299-
$over31 = count(array_filter($ints, function (int $int) {
303+
$over31 = count(array_filter($ints, function (int $int): bool {
300304
return $int > 31;
301305
}));
302-
$under1 = count(array_filter($ints, function (int $int) {
306+
$under1 = count(array_filter($ints, function (int $int): bool {
303307
return $int <= 0;
304308
}));
305309

@@ -313,7 +317,7 @@ protected static function checkDate(array $ints)
313317
[$ints[0], [$ints[1], $ints[2]]], // year first
314318
];
315319

316-
foreach ($possibleYearSplits as list($year, $rest)) {
320+
foreach ($possibleYearSplits as [$year, $rest]) {
317321
if ($year >= static::MIN_YEAR && $year <= static::MAX_YEAR) {
318322
if ($dm = static::mapIntsToDayMonth($rest)) {
319323
return [
@@ -329,7 +333,7 @@ protected static function checkDate(array $ints)
329333
}
330334
}
331335

332-
foreach ($possibleYearSplits as list($year, $rest)) {
336+
foreach ($possibleYearSplits as [$year, $rest]) {
333337
if ($dm = static::mapIntsToDayMonth($rest)) {
334338
return [
335339
'year' => static::twoToFourDigitYear($year),
@@ -349,7 +353,7 @@ protected static function checkDate(array $ints)
349353
*/
350354
protected static function mapIntsToDayMonth(array $ints)
351355
{
352-
foreach ([$ints, array_reverse($ints)] as list($d, $m)) {
356+
foreach ([$ints, array_reverse($ints)] as [$d, $m]) {
353357
if ($d >= 1 && $d <= 31 && $m >= 1 && $m <= 12) {
354358
return [
355359
'day' => $d,

src/Matchers/DictionaryMatch.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
<?php
22

3+
declare(strict_types=1);
4+
35
namespace ZxcvbnPhp\Matchers;
46

7+
use JetBrains\PhpStorm\ArrayShape;
58
use ZxcvbnPhp\Matcher;
69

710
class DictionaryMatch extends BaseMatch
@@ -33,7 +36,7 @@ class DictionaryMatch extends BaseMatch
3336
protected const ALL_LOWER = "/^[^A-Z]+$/u";
3437

3538
/**
36-
* Match occurences of dictionary words in password.
39+
* Match occurrences of dictionary words in password.
3740
*
3841
* @param string $password
3942
* @param array $userInputs
@@ -84,6 +87,11 @@ public function __construct(string $password, int $begin, int $end, string $toke
8487
}
8588
}
8689

90+
/**
91+
* @param bool $isSoleMatch
92+
* @return array
93+
*/
94+
#[ArrayShape(['warning' => 'string', 'suggestions' => 'string[]'])]
8795
public function getFeedback(bool $isSoleMatch): array
8896
{
8997
$startUpper = '/^[A-Z][^A-Z]+$/u';

src/Matchers/L33tMatch.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
<?php
22

3+
declare(strict_types=1);
4+
35
namespace ZxcvbnPhp\Matchers;
46

7+
use JetBrains\PhpStorm\ArrayShape;
58
use ZxcvbnPhp\Matcher;
69

710
/**
@@ -95,6 +98,7 @@ public function __construct(string $password, int $begin, int $end, string $toke
9598
}
9699
}
97100

101+
#[ArrayShape(['warning' => 'string', 'suggestions' => 'string[]'])]
98102
public function getFeedback(bool $isSoleMatch): array
99103
{
100104
$feedback = parent::getFeedback($isSoleMatch);

src/Matchers/MatchInterface.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
<?php
22

3+
declare(strict_types=1);
4+
35
namespace ZxcvbnPhp\Matchers;
46

57
interface MatchInterface

src/Matchers/RepeatMatch.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
<?php
22

3+
declare(strict_types=1);
4+
35
namespace ZxcvbnPhp\Matchers;
46

7+
use JetBrains\PhpStorm\ArrayShape;
58
use ZxcvbnPhp\Matcher;
69
use ZxcvbnPhp\Scorer;
710

@@ -28,7 +31,7 @@ class RepeatMatch extends BaseMatch
2831
/**
2932
* Match 3 or more repeated characters.
3033
*
31-
* @param $password
34+
* @param string $password
3235
* @param array $userInputs
3336
* @return RepeatMatch[]
3437
*/
@@ -82,6 +85,7 @@ public static function match(string $password, array $userInputs = []): array
8285
return $matches;
8386
}
8487

88+
#[ArrayShape(['warning' => 'string', 'suggestions' => 'string[]'])]
8589
public function getFeedback(bool $isSoleMatch): array
8690
{
8791
$warning = mb_strlen($this->repeatedChar) == 1

0 commit comments

Comments
 (0)