Skip to content

Commit 126c99b

Browse files
authored
fix: remove mbstring dependency for better PHP compatibility (#262)
* fix: remove mbstring dependency for better PHP compatibility The library was using several mbstring functions that are either unavailable in older PHP versions (mb_trim requires PHP 8.4+) or unnecessary for ASCII-only data. Changes: - Replace mb_trim with trim (mb_trim requires PHP 8.4+) - Replace mb_strtoupper with strtoupper (secrets are base32/ASCII) - Replace mb_strtolower with strtolower (algorithm names are ASCII) - Replace mb_substr with substr (removing leading '/' from URIs) - Replace mb_strlen with strlen in tests (base32 secrets are ASCII) - Remove ext-mbstring dependency from composer.json - Remove MBString mutator config from infection.json.dist All replacements are safe because the library only processes: - Base32-encoded secrets (A-Z, 2-7, = characters only) - Algorithm names (sha1, sha256, etc.) - URI paths (always start with ASCII '/' character) Fixes #261 * fix: add missing strlen function import in test files
1 parent f825b5d commit 126c99b

File tree

6 files changed

+13
-18
lines changed

6 files changed

+13
-18
lines changed

.ci-tools/infection.json.dist

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,6 @@
1414
"\\$this->logger.*",
1515
"\\$this->cache->save.*",
1616
"parent::build(\\$container);"
17-
],
18-
"MBString": {
19-
"settings": {
20-
"mb_substr": false,
21-
"mb_strlen": false
22-
}
23-
}
17+
]
2418
}
2519
}

composer.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
],
1818
"require": {
1919
"php": ">=8.1",
20-
"ext-mbstring": "*",
2120
"paragonie/constant_time_encoding": "^2.0 || ^3.0",
2221
"psr/clock": "^1.0",
2322
"symfony/deprecation-contracts": "^3.2"

src/Factory.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ private static function populateParameters(OTPInterface $otp, Url $data): void
5757
private static function populateOTP(OTPInterface $otp, Url $data): void
5858
{
5959
self::populateParameters($otp, $data);
60-
$result = explode(':', rawurldecode(mb_substr($data->getPath(), 1)));
60+
$result = explode(':', rawurldecode(substr($data->getPath(), 1)));
6161

6262
if (count($result) < 2) {
6363
$otp->setIssuerIncludedAsParameter(false);
@@ -105,7 +105,7 @@ private static function createOTP(Url $parsed_url, ClockInterface $clock): OTPIn
105105
*/
106106
private static function getLabel(string $data): string
107107
{
108-
$result = explode(':', rawurldecode(mb_substr($data, 1)));
108+
$result = explode(':', rawurldecode(substr($data, 1)));
109109
$label = count($result) === 2 ? $result[1] : $result[0];
110110
$label !== '' || throw new InvalidProvisioningUriException('Label must not be empty.');
111111

src/OTP.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -339,9 +339,9 @@ protected function getParameterMap(): array
339339

340340
return $value;
341341
},
342-
'secret' => static fn (string $value): string => mb_strtoupper(mb_trim($value, '=')),
342+
'secret' => static fn (string $value): string => strtoupper(trim($value, '=')),
343343
'algorithm' => static function (string $value): string {
344-
$value = mb_strtolower($value);
344+
$value = strtolower($value);
345345
in_array($value, hash_algos(), true) || throw new InvalidParameterException(
346346
sprintf('The "%s" digest is not supported.', $value),
347347
'algorithm',

tests/HOTPTest.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use PHPUnit\Framework\Attributes\Test;
1010
use PHPUnit\Framework\TestCase;
1111
use RuntimeException;
12+
use function strlen;
1213

1314
/**
1415
* @internal
@@ -274,7 +275,7 @@ public function generateWithDefaultSecretSize(): void
274275

275276
static::assertMatchesRegularExpression('/^[A-Z2-7]+$/', $otp->getSecret());
276277
// Default secret size is 64 bytes, which encodes to ceil(64 * 8 / 5) = 103 base32 chars
277-
static::assertSame(103, mb_strlen($otp->getSecret()));
278+
static::assertSame(103, strlen($otp->getSecret()));
278279
}
279280

280281
#[Test]
@@ -284,7 +285,7 @@ public function generateWithCustomSecretSize(): void
284285

285286
static::assertMatchesRegularExpression('/^[A-Z2-7]+$/', $otp->getSecret());
286287
// 16 bytes encodes to ceil(16 * 8 / 5) = 26 base32 chars
287-
static::assertSame(26, mb_strlen($otp->getSecret()));
288+
static::assertSame(26, strlen($otp->getSecret()));
288289
}
289290

290291
#[Test]
@@ -294,7 +295,7 @@ public function generateWithCustomSecretSizeViaCreate(): void
294295

295296
static::assertMatchesRegularExpression('/^[A-Z2-7]+$/', $otp->getSecret());
296297
// 32 bytes encodes to ceil(32 * 8 / 5) = 52 base32 chars
297-
static::assertSame(52, mb_strlen($otp->getSecret()));
298+
static::assertSame(52, strlen($otp->getSecret()));
298299
}
299300

300301
#[Test]

tests/TOTPTest.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Psr\Clock\ClockInterface;
1717
use RuntimeException;
1818
use function assert;
19+
use function strlen;
1920

2021
/**
2122
* @internal
@@ -509,7 +510,7 @@ public function generateWithDefaultSecretSize(): void
509510

510511
static::assertMatchesRegularExpression('/^[A-Z2-7]+$/', $otp->getSecret());
511512
// Default secret size is 64 bytes, which encodes to ceil(64 * 8 / 5) = 103 base32 chars
512-
static::assertSame(103, mb_strlen($otp->getSecret()));
513+
static::assertSame(103, strlen($otp->getSecret()));
513514
}
514515

515516
#[Test]
@@ -519,7 +520,7 @@ public function generateWithCustomSecretSize(): void
519520

520521
static::assertMatchesRegularExpression('/^[A-Z2-7]+$/', $otp->getSecret());
521522
// 16 bytes encodes to ceil(16 * 8 / 5) = 26 base32 chars
522-
static::assertSame(26, mb_strlen($otp->getSecret()));
523+
static::assertSame(26, strlen($otp->getSecret()));
523524
}
524525

525526
#[Test]
@@ -530,7 +531,7 @@ public function generateWithCustomSecretSizeViaCreate(): void
530531

531532
static::assertMatchesRegularExpression('/^[A-Z2-7]+$/', $otp->getSecret());
532533
// 32 bytes encodes to ceil(32 * 8 / 5) = 52 base32 chars
533-
static::assertSame(52, mb_strlen($otp->getSecret()));
534+
static::assertSame(52, strlen($otp->getSecret()));
534535
}
535536

536537
#[Test]

0 commit comments

Comments
 (0)