Skip to content

Commit

Permalink
Update regex to restrict words containing digit only at the beginning…
Browse files Browse the repository at this point in the history
… or the end of the ID
  • Loading branch information
GromNaN committed Jan 3, 2025
1 parent b554a35 commit ac5e827
Showing 1 changed file with 50 additions and 17 deletions.
67 changes: 50 additions & 17 deletions src/Sqids.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@

class Sqids implements SqidsInterface
{
private const MIN_LENGTH_LIMIT = 255;

final public const DEFAULT_ALPHABET = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
final public const DEFAULT_MIN_LENGTH = 0;
final public const DEFAULT_BLOCKLIST = [
Expand Down Expand Up @@ -237,7 +239,7 @@ class Sqids implements SqidsInterface

protected MathInterface $math;

protected ?string $blocklistRegex = null;
protected ?string $blocklistRegex;

/** @throws InvalidArgumentException */
public function __construct(
Expand All @@ -263,25 +265,12 @@ public function __construct(
throw new InvalidArgumentException('Alphabet must contain unique characters');
}

$minLengthLimit = 255;
if ($minLength < 0 || $minLength > $minLengthLimit) {
throw new InvalidArgumentException(
'Minimum length has to be between 0 and ' . $minLengthLimit,
);
}

$filteredBlocklist = [];
foreach ($blocklist as $word) {
if (strlen((string) $word) >= 3) {
$filteredBlocklist[] = strtr(preg_quote((string) $word, '/'), self::LEET);
}
}
if ($filteredBlocklist) {
$this->blocklistRegex = '/(' . implode('|', $filteredBlocklist) . ')/i';
if ($minLength < 0 || $minLength > self::MIN_LENGTH_LIMIT) {
throw new InvalidArgumentException('Minimum length has to be between 0 and ' . self::MIN_LENGTH_LIMIT);
}

$this->blocklistRegex = $this->buildBlocklistRegex();
$this->alphabet = $this->shuffle($alphabet);
$this->blocklist = $filteredBlocklist;
}

/**
Expand Down Expand Up @@ -471,4 +460,48 @@ protected function getMathExtension(): MathInterface

throw new RuntimeException('Missing math extension for Sqids, install either bcmath or gmp.');
}

protected function buildBlocklistRegex(): ?string
{
$wordsMatchingExactly = [];
$wordsMatchingBeginningOrEnd = [];
$wordMatchingAnywhere = [];

foreach ($this->blocklist as $word) {
$word = (string) $word;
if (strlen($word) <= 3) {
$wordsMatchingExactly[] = preg_quote($word, '/');
} else {
$word = preg_quote($word, '/');
$leet = strtr($word, self::LEET);
if (!preg_match('/\d/', $word)) {
$wordMatchingAnywhere[] = $word;
} elseif ($leet === $word) {
$wordsMatchingBeginningOrEnd[] = $word;
}

if ($leet !== $word) {
$wordsMatchingBeginningOrEnd[] = $leet;
}
}
}

$regexParts = [];
if ($wordsMatchingExactly) {
$regexParts[] = '^('.implode('|', $wordsMatchingExactly).')$';
}
if ($wordsMatchingBeginningOrEnd) {
$regexParts[] = '^('.implode('|', $wordsMatchingBeginningOrEnd).')';
$regexParts[] = '('.implode('|', $wordsMatchingBeginningOrEnd).')$';
}
if ($wordMatchingAnywhere) {
$regexParts[] = '('.implode('|', $wordMatchingAnywhere).')';
}

if ($regexParts) {
return '/(' . implode('|', $regexParts) . ')/i';
}

return null;
}
}

0 comments on commit ac5e827

Please sign in to comment.