1<?php 2 3namespace IPLib; 4 5use IPLib\Address\AddressInterface; 6 7/** 8 * Factory methods to build class instances. 9 */ 10class Factory 11{ 12 /** 13 * Parse an IP address string. 14 * 15 * @param string $address the address to parse 16 * @param bool $mayIncludePort set to false to avoid parsing addresses with ports 17 * @param bool $mayIncludeZoneID set to false to avoid parsing IPv6 addresses with zone IDs (see RFC 4007) 18 * 19 * @return \IPLib\Address\AddressInterface|null 20 */ 21 public static function addressFromString($address, $mayIncludePort = true, $mayIncludeZoneID = true) 22 { 23 $result = null; 24 if ($result === null) { 25 $result = Address\IPv4::fromString($address, $mayIncludePort); 26 } 27 if ($result === null) { 28 $result = Address\IPv6::fromString($address, $mayIncludePort, $mayIncludeZoneID); 29 } 30 31 return $result; 32 } 33 34 /** 35 * Convert a byte array to an address instance. 36 * 37 * @param int[]|array $bytes 38 * 39 * @return \IPLib\Address\AddressInterface|null 40 */ 41 public static function addressFromBytes(array $bytes) 42 { 43 $result = null; 44 if ($result === null) { 45 $result = Address\IPv4::fromBytes($bytes); 46 } 47 if ($result === null) { 48 $result = Address\IPv6::fromBytes($bytes); 49 } 50 51 return $result; 52 } 53 54 /** 55 * Parse an IP range string. 56 * 57 * @param string $range 58 * 59 * @return \IPLib\Range\RangeInterface|null 60 */ 61 public static function rangeFromString($range) 62 { 63 $result = null; 64 if ($result === null) { 65 $result = Range\Subnet::fromString($range); 66 } 67 if ($result === null) { 68 $result = Range\Pattern::fromString($range); 69 } 70 if ($result === null) { 71 $result = Range\Single::fromString($range); 72 } 73 74 return $result; 75 } 76 77 /** 78 * Create a Range instance starting from its boundaries. 79 * 80 * @param string|\IPLib\Address\AddressInterface $from 81 * @param string|\IPLib\Address\AddressInterface $to 82 * 83 * @return \IPLib\Range\RangeInterface|null 84 */ 85 public static function rangeFromBoundaries($from, $to) 86 { 87 $result = null; 88 $invalid = false; 89 foreach (array('from', 'to') as $param) { 90 if (!($$param instanceof AddressInterface)) { 91 $$param = (string) $$param; 92 if ($$param === '') { 93 $$param = null; 94 } else { 95 $$param = static::addressFromString($$param); 96 if ($$param === null) { 97 $invalid = true; 98 } 99 } 100 } 101 } 102 if ($invalid === false) { 103 $result = static::rangeFromBoundaryAddresses($from, $to); 104 } 105 106 return $result; 107 } 108 109 /** 110 * @param \IPLib\Address\AddressInterface $from 111 * @param \IPLib\Address\AddressInterface $to 112 * 113 * @return \IPLib\Range\RangeInterface|null 114 */ 115 protected static function rangeFromBoundaryAddresses(AddressInterface $from = null, AddressInterface $to = null) 116 { 117 if ($from === null && $to === null) { 118 $result = null; 119 } elseif ($to === null) { 120 $result = Range\Single::fromAddress($from); 121 } elseif ($from === null) { 122 $result = Range\Single::fromAddress($to); 123 } else { 124 $result = null; 125 $addressType = $from->getAddressType(); 126 if ($addressType === $to->getAddressType()) { 127 $cmp = strcmp($from->getComparableString(), $to->getComparableString()); 128 if ($cmp === 0) { 129 $result = Range\Single::fromAddress($from); 130 } else { 131 if ($cmp > 0) { 132 list($from, $to) = array($to, $from); 133 } 134 $fromBytes = $from->getBytes(); 135 $toBytes = $to->getBytes(); 136 $numBytes = count($fromBytes); 137 $sameBits = 0; 138 for ($byteIndex = 0; $byteIndex < $numBytes; ++$byteIndex) { 139 $fromByte = $fromBytes[$byteIndex]; 140 $toByte = $toBytes[$byteIndex]; 141 if ($fromByte === $toByte) { 142 $sameBits += 8; 143 } else { 144 $differentBitsInByte = decbin($fromByte ^ $toByte); 145 $sameBits += 8 - strlen($differentBitsInByte); 146 break; 147 } 148 } 149 $result = static::rangeFromString($from->toString(true).'/'.(string) $sameBits); 150 } 151 } 152 } 153 154 return $result; 155 } 156} 157