lockIPv4PartCount = $lockIPv4PartCount; $this->lockIPv6PartCount = $lockIPv6PartCount; } public function getSessionIpLock(string $ipAddress): string { if ($this->lockIPv4PartCount === 0 && $this->lockIPv6PartCount === 0) { return static::DISABLED_LOCK_VALUE; } if ($this->isIpv6Address($ipAddress)) { return $this->getIpLockPartForIpv6Address($ipAddress); } return $this->getIpLockPartForIpv4Address($ipAddress); } public function validateRemoteAddressAgainstSessionIpLock(string $ipAddress, string $sessionIpLock): bool { if ($sessionIpLock === static::DISABLED_LOCK_VALUE) { return true; } $ipToCompare = $this->isIpv6Address($ipAddress) ? $this->getIpLockPartForIpv6Address($ipAddress) : $this->getIpLockPartForIpv4Address($ipAddress); return $ipToCompare === $sessionIpLock; } protected function getIpLockPart(string $ipAddress, int $numberOfParts, int $maxParts, string $delimiter): string { if ($numberOfParts >= $maxParts) { return $ipAddress; } $numberOfParts = MathUtility::forceIntegerInRange($numberOfParts, 1, $maxParts); $ipParts = explode($delimiter, $ipAddress); for ($a = $maxParts; $a > $numberOfParts; $a--) { $ipPartValue = $delimiter === '.' ? '0' : str_pad('', strlen($ipParts[$a - 1]), '0'); $ipParts[$a - 1] = $ipPartValue; } return implode($delimiter, $ipParts); } protected function getIpLockPartForIpv4Address(string $ipAddress): string { if ($this->lockIPv4PartCount === 0) { return static::DISABLED_LOCK_VALUE; } return $this->getIpLockPart($ipAddress, $this->lockIPv4PartCount, 4, '.'); } protected function getIpLockPartForIpv6Address(string $ipAddress): string { if ($this->lockIPv6PartCount === 0) { return static::DISABLED_LOCK_VALUE; } // inet_pton also takes care of IPv4-mapped addresses (see https://en.wikipedia.org/wiki/IPv6_address#Representation) $unpacked = unpack('H*hex', (string)inet_pton($ipAddress)) ?: []; $expandedAddress = rtrim(chunk_split($unpacked['hex'] ?? '', 4, ':'), ':'); return $this->getIpLockPart($expandedAddress, $this->lockIPv6PartCount, 8, ':'); } protected function isIpv6Address(string $ipAddress): bool { return str_contains($ipAddress, ':'); } }