annotate vendor/symfony/http-foundation/IpUtils.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 129ea1e6d783
children
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 /*
Chris@0 4 * This file is part of the Symfony package.
Chris@0 5 *
Chris@0 6 * (c) Fabien Potencier <fabien@symfony.com>
Chris@0 7 *
Chris@0 8 * For the full copyright and license information, please view the LICENSE
Chris@0 9 * file that was distributed with this source code.
Chris@0 10 */
Chris@0 11
Chris@0 12 namespace Symfony\Component\HttpFoundation;
Chris@0 13
Chris@0 14 /**
Chris@0 15 * Http utility functions.
Chris@0 16 *
Chris@0 17 * @author Fabien Potencier <fabien@symfony.com>
Chris@0 18 */
Chris@0 19 class IpUtils
Chris@0 20 {
Chris@17 21 private static $checkedIps = [];
Chris@12 22
Chris@0 23 /**
Chris@0 24 * This class should not be instantiated.
Chris@0 25 */
Chris@0 26 private function __construct()
Chris@0 27 {
Chris@0 28 }
Chris@0 29
Chris@0 30 /**
Chris@0 31 * Checks if an IPv4 or IPv6 address is contained in the list of given IPs or subnets.
Chris@0 32 *
Chris@0 33 * @param string $requestIp IP to check
Chris@0 34 * @param string|array $ips List of IPs or subnets (can be a string if only a single one)
Chris@0 35 *
Chris@0 36 * @return bool Whether the IP is valid
Chris@0 37 */
Chris@0 38 public static function checkIp($requestIp, $ips)
Chris@0 39 {
Chris@17 40 if (!\is_array($ips)) {
Chris@17 41 $ips = [$ips];
Chris@0 42 }
Chris@0 43
Chris@0 44 $method = substr_count($requestIp, ':') > 1 ? 'checkIp6' : 'checkIp4';
Chris@0 45
Chris@0 46 foreach ($ips as $ip) {
Chris@0 47 if (self::$method($requestIp, $ip)) {
Chris@0 48 return true;
Chris@0 49 }
Chris@0 50 }
Chris@0 51
Chris@0 52 return false;
Chris@0 53 }
Chris@0 54
Chris@0 55 /**
Chris@0 56 * Compares two IPv4 addresses.
Chris@0 57 * In case a subnet is given, it checks if it contains the request IP.
Chris@0 58 *
Chris@0 59 * @param string $requestIp IPv4 address to check
Chris@0 60 * @param string $ip IPv4 address or subnet in CIDR notation
Chris@0 61 *
Chris@0 62 * @return bool Whether the request IP matches the IP, or whether the request IP is within the CIDR subnet
Chris@0 63 */
Chris@0 64 public static function checkIp4($requestIp, $ip)
Chris@0 65 {
Chris@12 66 $cacheKey = $requestIp.'-'.$ip;
Chris@12 67 if (isset(self::$checkedIps[$cacheKey])) {
Chris@12 68 return self::$checkedIps[$cacheKey];
Chris@12 69 }
Chris@12 70
Chris@0 71 if (!filter_var($requestIp, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
Chris@12 72 return self::$checkedIps[$cacheKey] = false;
Chris@0 73 }
Chris@0 74
Chris@0 75 if (false !== strpos($ip, '/')) {
Chris@0 76 list($address, $netmask) = explode('/', $ip, 2);
Chris@0 77
Chris@14 78 if ('0' === $netmask) {
Chris@12 79 return self::$checkedIps[$cacheKey] = filter_var($address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4);
Chris@0 80 }
Chris@0 81
Chris@0 82 if ($netmask < 0 || $netmask > 32) {
Chris@12 83 return self::$checkedIps[$cacheKey] = false;
Chris@0 84 }
Chris@0 85 } else {
Chris@0 86 $address = $ip;
Chris@0 87 $netmask = 32;
Chris@0 88 }
Chris@0 89
Chris@14 90 if (false === ip2long($address)) {
Chris@14 91 return self::$checkedIps[$cacheKey] = false;
Chris@14 92 }
Chris@14 93
Chris@12 94 return self::$checkedIps[$cacheKey] = 0 === substr_compare(sprintf('%032b', ip2long($requestIp)), sprintf('%032b', ip2long($address)), 0, $netmask);
Chris@0 95 }
Chris@0 96
Chris@0 97 /**
Chris@0 98 * Compares two IPv6 addresses.
Chris@0 99 * In case a subnet is given, it checks if it contains the request IP.
Chris@0 100 *
Chris@0 101 * @author David Soria Parra <dsp at php dot net>
Chris@0 102 *
Chris@0 103 * @see https://github.com/dsp/v6tools
Chris@0 104 *
Chris@0 105 * @param string $requestIp IPv6 address to check
Chris@0 106 * @param string $ip IPv6 address or subnet in CIDR notation
Chris@0 107 *
Chris@0 108 * @return bool Whether the IP is valid
Chris@0 109 *
Chris@0 110 * @throws \RuntimeException When IPV6 support is not enabled
Chris@0 111 */
Chris@0 112 public static function checkIp6($requestIp, $ip)
Chris@0 113 {
Chris@12 114 $cacheKey = $requestIp.'-'.$ip;
Chris@12 115 if (isset(self::$checkedIps[$cacheKey])) {
Chris@12 116 return self::$checkedIps[$cacheKey];
Chris@12 117 }
Chris@12 118
Chris@17 119 if (!((\extension_loaded('sockets') && \defined('AF_INET6')) || @inet_pton('::1'))) {
Chris@0 120 throw new \RuntimeException('Unable to check Ipv6. Check that PHP was not compiled with option "disable-ipv6".');
Chris@0 121 }
Chris@0 122
Chris@0 123 if (false !== strpos($ip, '/')) {
Chris@0 124 list($address, $netmask) = explode('/', $ip, 2);
Chris@0 125
Chris@14 126 if ('0' === $netmask) {
Chris@14 127 return (bool) unpack('n*', @inet_pton($address));
Chris@14 128 }
Chris@14 129
Chris@0 130 if ($netmask < 1 || $netmask > 128) {
Chris@12 131 return self::$checkedIps[$cacheKey] = false;
Chris@0 132 }
Chris@0 133 } else {
Chris@0 134 $address = $ip;
Chris@0 135 $netmask = 128;
Chris@0 136 }
Chris@0 137
Chris@0 138 $bytesAddr = unpack('n*', @inet_pton($address));
Chris@0 139 $bytesTest = unpack('n*', @inet_pton($requestIp));
Chris@0 140
Chris@0 141 if (!$bytesAddr || !$bytesTest) {
Chris@12 142 return self::$checkedIps[$cacheKey] = false;
Chris@0 143 }
Chris@0 144
Chris@0 145 for ($i = 1, $ceil = ceil($netmask / 16); $i <= $ceil; ++$i) {
Chris@0 146 $left = $netmask - 16 * ($i - 1);
Chris@0 147 $left = ($left <= 16) ? $left : 16;
Chris@0 148 $mask = ~(0xffff >> $left) & 0xffff;
Chris@0 149 if (($bytesAddr[$i] & $mask) != ($bytesTest[$i] & $mask)) {
Chris@12 150 return self::$checkedIps[$cacheKey] = false;
Chris@0 151 }
Chris@0 152 }
Chris@0 153
Chris@12 154 return self::$checkedIps[$cacheKey] = true;
Chris@0 155 }
Chris@0 156 }