Page MenuHomeDevCentral

No OneTemporary

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

Mime Type
text/x-diff
Expires
Mon, Nov 25, 01:38 (17 h, 57 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2259344
Default Alt Text
(8 KB)

Event Timeline