Page Menu
Home
DevCentral
Search
Configure Global Search
Log In
Files
F3767592
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
8 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/Network/IP.php b/src/Network/IP.php
index e6d0f39..68eb4c4 100644
--- a/src/Network/IP.php
+++ b/src/Network/IP.php
@@ -1,31 +1,59 @@
<?php
declare(strict_types=1);
namespace Keruald\OmniTools\Network;
-class IP {
+use InvalidArgumentException;
+
+abstract class IP {
+
+ ///
+ /// Helper methods
+ ///
public static function isIP (string $ip) : bool {
return self::isIPv4($ip) || self::isIPv6($ip);
}
public static function isIPv4 (string $ip) : bool {
return filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false;
}
public static function isIPv6 (string $ip) : bool {
return filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false;
}
public static function isLoopback (string $ip) : bool {
$ranges = IPRange::getLoopbackRanges();
foreach ($ranges as $range) {
if ($range->contains($ip)) {
return true;
}
}
return false;
}
+ ///
+ /// Constructor
+ ///
+
+ public static function from (string $ip) : IP {
+ if (self::isIPv4($ip)) {
+ return new IPv4($ip);
+ }
+
+ if (self::isIPv6($ip)) {
+ $ipv6 = new IPv6($ip);
+ $ipv6->normalize();
+ return $ipv6;
+ }
+
+ throw new InvalidArgumentException;
+ }
+
+ public abstract function __toString () : string;
+
+ public abstract function getDomain () : int;
+
}
diff --git a/src/Network/IPv4.php b/src/Network/IPv4.php
new file mode 100644
index 0000000..b4c184c
--- /dev/null
+++ b/src/Network/IPv4.php
@@ -0,0 +1,56 @@
+<?php
+declare(strict_types=1);
+
+namespace Keruald\OmniTools\Network;
+
+use InvalidArgumentException;
+
+class IPv4 extends IP {
+
+ ///
+ /// Constants
+ ///
+
+ const DOMAIN = 2; // AF_INET
+
+ ///
+ /// Properties
+ ///
+
+ private string $ip;
+
+ ///
+ /// Constructors
+ ///
+
+ public function __construct (string $ip) {
+ $this->ip = $ip;
+ }
+
+ public static function from (string $ip) : self {
+ $ipv4 = new self($ip);
+
+ if (!$ipv4->isValid()) {
+ throw new InvalidArgumentException("Address is not a valid IPv4.");
+ }
+
+ return $ipv4;
+ }
+
+ public function isValid () : bool {
+ return IP::isIPv4($this->ip);
+ }
+
+ public function getDomain () : int {
+ return self::DOMAIN; // AF_INET
+ }
+
+ ///
+ /// Magic methods
+ ///
+
+ public function __toString () : string {
+ return $this->ip;
+ }
+
+}
diff --git a/src/Network/IPv6.php b/src/Network/IPv6.php
index faa475c..eee126c 100644
--- a/src/Network/IPv6.php
+++ b/src/Network/IPv6.php
@@ -1,98 +1,112 @@
<?php
namespace Keruald\OmniTools\Network;
use InvalidArgumentException;
class IPv6 extends IP {
+ ///
+ /// Constants
+ ///
+
+ const DOMAIN = 10; // AF_INET6
+
+ ///
+ /// Properties
+ ///
+
/**
* @var string
*/
private $ip;
///
/// Constructors
///
public function __construct (string $ip) {
$this->ip = $ip;
}
public static function from (string $ip) : self {
$ipv6 = new self($ip);
if (!$ipv6->isValid()) {
throw new InvalidArgumentException;
}
$ipv6->normalize();
return $ipv6;
}
public static function fromBinaryBits (array $bits) : self {
$fullBits = $bits + array_fill(0, 128, 0);
$hextets = [];
for ($i = 0 ; $i < 8 ; $i++) {
// Read 16 bits
$slice = implode("", array_slice($fullBits, $i * 16, 16));
$hextets[] = base_convert($slice, 2, 16);
}
return self::from(implode(":", $hextets));
}
///
/// Helper methods
///
public function isValid () : bool {
return IP::isIPv6($this->ip);
}
+ public function getDomain () : int {
+ return self::DOMAIN; // AF_INET6
+ }
+
public function increment (int $increment = 1) : self {
if ($increment === 0) {
return $this;
}
if ($increment < 0) {
throw new InvalidArgumentException("This method doesn't support decrementation.");
}
$ipAsNumericBinary = inet_pton($this->ip);
// See https://gist.github.com/little-apps/88bbd23576008a84e0b6
$i = strlen($ipAsNumericBinary) - 1;
$remainder = $increment;
while ($remainder > 0 && $i >= 0) {
$sum = ord($ipAsNumericBinary[$i]) + $remainder;
$remainder = $sum / 256;
$ipAsNumericBinary[$i] = chr($sum % 256);
--$i;
}
$this->ip = inet_ntop($ipAsNumericBinary);
return $this;
}
public function normalize () : self {
$this->ip = inet_ntop(inet_pton($this->ip));
return $this;
}
public function isNormalized() : bool {
return $this->ip === inet_ntop(inet_pton($this->ip));
}
///
/// Magic methods
///
public function __toString () : string {
return $this->ip;
}
}
diff --git a/src/Network/Port.php b/src/Network/Port.php
new file mode 100644
index 0000000..439b325
--- /dev/null
+++ b/src/Network/Port.php
@@ -0,0 +1,25 @@
+<?php
+declare(strict_types=1);
+
+namespace Keruald\OmniTools\Network;
+
+class Port {
+
+ ///
+ /// Properties
+ ///
+
+ public Protocol $protocol;
+
+ public int $number;
+
+ ///
+ /// Constructor
+ ///
+
+ public function __construct (int $number, Protocol $protocol = Protocol::TCP) {
+ $this->number = $number;
+ $this->protocol = $protocol;
+ }
+
+}
diff --git a/src/Network/Protocol.php b/src/Network/Protocol.php
new file mode 100644
index 0000000..6c005cf
--- /dev/null
+++ b/src/Network/Protocol.php
@@ -0,0 +1,11 @@
+<?php
+declare(strict_types=1);
+
+namespace Keruald\OmniTools\Network;
+
+enum Protocol {
+ case TCP;
+ case UDP;
+ case SCTP;
+ case DCCP;
+}
diff --git a/src/Network/SocketAddress.php b/src/Network/SocketAddress.php
new file mode 100644
index 0000000..2a80d9b
--- /dev/null
+++ b/src/Network/SocketAddress.php
@@ -0,0 +1,93 @@
+<?php
+declare(strict_types=1);
+
+namespace Keruald\OmniTools\Network;
+
+use RuntimeException;
+
+class SocketAddress {
+
+ ///
+ /// Constants
+ ///
+
+ const DEFAULT_TIMEOUT = 10;
+
+ const PROTOCOL_TCP = 6; // getprotobyname("tcp")
+
+ ///
+ /// Properties
+ ///
+
+ public IP $address;
+
+ public Port $port;
+
+ ///
+ /// Constructors
+ ///
+
+ public function __construct (IP $address, Port $port) {
+ $this->address = $address;
+ $this->port = $port;
+ }
+
+ /**
+ * Gets new socket address from specified IP, port and protocol information.
+ *
+ * This method takes care to creates the underlying IP and Port object.
+ */
+ public static function from (
+ string $ip,
+ int $port, Protocol $protocol = Protocol::TCP
+ ) : self {
+ return new self(
+ IP::from($ip),
+ new Port($port, $protocol),
+ );
+ }
+
+ ///
+ /// Interact with socket
+ ///
+
+ /**
+ * Determines if a TCP socket is open
+ *
+ * @throws RuntimeException if the protocol isn't TCP
+ * @return bool if the TCP socket accepts a connection
+ */
+ public function isOpen() : bool {
+ if ($this->port->protocol !== Protocol::TCP) {
+ throw new RuntimeException("Check if a port is open is only implemented for TCP.");
+ }
+
+ if (!function_exists("socket_create")) {
+ return $this->isOpenLegacy();
+ }
+
+ $socket = socket_create($this->address->getDomain(), SOCK_STREAM, self::PROTOCOL_TCP);
+ $result = socket_connect($socket, $this->address->__toString(), $this->port->number);
+ socket_close($socket);
+
+ return $result;
+ }
+
+ private function isOpenLegacy () : bool {
+ $fp = @fsockopen(
+ $this->address->__toString(),
+ $this->port->number,
+ $errorCode, $errorMessage,
+ self::DEFAULT_TIMEOUT
+ );
+
+ if ($fp) {
+ fclose($fp);
+
+ return true;
+ }
+
+ return false;
+ }
+
+}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Mon, Nov 25, 01:38 (16 h, 9 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2259344
Default Alt Text
(8 KB)
Attached To
Mode
rKOT Keruald OmniTools
Attached
Detach File
Event Timeline
Log In to Comment