Networking utilities

When working on PHP projects, I sometimes need some networking utilities. This repository provides them. You can think about executing a ping request, scanning a network, getting IP information, etcetera.

For those purposes I wrote a library that's been tested on both Windows and Linux servers.

Below you'll find the documentation of the library. Source code can be found at https://bitbucket.org/garrcomm/php-networking-utilities.

Introduction

When working on PHP projects, I often need some network related methods. This repository contains a list of classes that help with that. This package works on PHP 7.4 and higer, including PHP 8.

These services are currently included:
The Dns Service is a wrapper for nslookup that gives detailed and structured responses.
The IpTools Service wraps around some IP related commands and also returns structured objects.

There are also a few very useful data models;
The Url Model is an object orientated wrapper around parse_url with the possibility to also modify URLs.
The Ipv4Address and Ipv4Range Models helps formatting IPv4 addresses and performs some subnet based calculations.
The MacAddress Model helps validating and formatting MAC addresses.
The DnsResult and DnsAnswer Models are returned by the Dns service.

All data models can be serialized with json_encode and var_export. Also, they can all be represented as a string.

How to install

You can install these utilities with Composer by running composer require garrcomm/networking-utilities or by copying the source files from the src folder.

Code quality

Code quality is checked with several tools to make sure everything is working properly and well documented. The following methods are in use:

OS Dependencies

These utilities should work on most Windows and Linux installations. For Linux, it can be possible that you'll need to install some additional packages (depending on the OS config we'll need the commands nslookup, ip, ipconfig, ifconfig, ping and/or arp). Whenever one of those commands is missing, a RuntimeException with code 127 will be thrown.

On most Linux distros these tools are already included though. Otherwise, it's easy to solve by locating the appropriate package (apt-file search --regexp 'bin/ping$' or yum provides ping, depending on your distro).

How to develop on this package

If you've installed Docker, you can execute these commands in the root of the project:

docker compose up -d
docker compose exec php bash

This will put you in a terminal with the same configuration as the pipelines used for automated testing of this code. In this terminal, you've got a few commands:

# Download all (development) dependencies
composer install

# Run code sniffer
vendor/bin/phpcs

# Run static analyser
vendor/bin/phpstan

# Run unit tests
vendor/bin/phpunit

In this container, the command line tools used in this package are also installed.


Available objects

Below are all available classes in this package. They're divided into two categories;

  • Services that executes all kind of actions
  • Models that contain data and a few methods to manipulate that data

Service\Dns

Class example

The Dns service wraps around nslookup and returns neat DNS lookup results. It's also possible to change the target nameserver.

$dns = new \Garrcomm\Netutils\Service\Dns();
$dns->setDnsServer('dns.google');
var_dump($dns->getMx('google.com'));

Class synopsis

class Dns {

    /* Constants */
    public const A = 'internet address';
    public const AAAA = 'AAAA address';
    public const CNAME = 'canonical name';
    public const MX = 'mail exchanger';
    public const NS = 'nameserver';
    public const TXT = 'text';

    /* Methods */
    public __construct(string dnsServer = 'dns.google')
    public getA(string domain): DnsResult
    public getAAAA(string domain): DnsResult
    public getCname(string domain): DnsResult
    public getDnsServer(): string
    public getMx(string domain): DnsResult
    public getNs(string domain): DnsResult
    public getTxt(string domain): DnsResult
    public setDnsServer(string dnsServer): void
}

Constants

Dns::A
    An IPv4 internet address (A record)

Dns::AAAA
    An IPv6 internet address (AAAA record)

Dns::CNAME
    An alias to another DNS record (CNAME record)

Dns::MX
    IP address(es) to an email server (MX record)

Dns::NS
    DNS names of all responsible nameservers (NS record)

Dns::TXT
    A record containing plain text, used for domain verification, SPF, DKIM, etc. (TXT record)

Methods

Service\IpTools

Class example

IpTools helps with basic IPv4 related stuff;

$tools = new \Garrcomm\Netutils\Service\IpTools();

// getLocalIpv4s() returns a list of all IPv4 addresses on the current machine
$ips = $tools->getLocalIpv4s();
foreach ($ips as $networkName => $ip) {
    echo 'Network ' . $networkName . ' has IP address ' . $ip->getIpAddress() . PHP_EOL;
}

// networkQuickScan returns a list of all IPv4 addresses that can be found within a network
$ip = new \Garrcomm\Netutils\Model\Ipv4Address('192.168.2.1', '255.255.255.0');
$ips = $tools->networkQuickScan($ip);
foreach ($ips as $mac => $ip) {
    echo 'System ' . $mac . ' has IP address ' . $ip->getIpAddress() . PHP_EOL;
}

// With getIpByMac you can get the IP based on a MAC address
$mac = new \Garrcomm\Netutils\Model\MacAddress('aa-bb-cc-dd-ee-ff');
$ip = $tools->getIpByMac($mac);
echo 'Mac address ' . $mac . ' resolves to ' . $ip . PHP_EOL;

// With isLocalIp you can look up if an IP address is a local IP address
$ips = ['192.168.0.1', '8.8.8.8', '10.0.0.1'];
foreach ($ips as $ip) {
    echo $ip . ' is ' . ($tools->isLocalIp($ip) ? 'a' : 'not a') . ' local IP' . PHP_EOL;
}

Class synopsis

class IpTools {

    /* Methods */
    public __construct(string operatingSystem = 'Linux')
    public getIpByMac(MacAddress macAddress, ?Ipv4Address networkInterface = null): Ipv4Address
    public getLocalIpv4s(): Ipv4Address[]
    public getMacByIp(Ipv4Address ipv4Address): MacAddress
    public isLocalIp(integer|string|Ipv4Address ipAddress): bool
    public networkQuickScan(Ipv4Address networkInterface): Ipv4Address[]
}

Methods

  • IpTools::__construct — Initializes IP tools
  • IpTools::getIpByMac — Looks up the matching IP address for a MAC address.
  • IpTools::getLocalIpv4s — Returns a list of all local IPv4 addresses
  • IpTools::getMacByIp — Returns the known MAC address by its IP address.
  • IpTools::isLocalIp — Returns true when the IP is a local IP
    The IANA has defined these IP addresses as private or local:
    10.0.0.0 to 10.255.255.255, a range that provides up to 16 million unique IP addresses.
    172.16.0.0 to 172.31.255.255, providing about 1 million unique IP addresses.
    192.168.0.0 to 192.168.255.255, which offers about 65,000 unique IP addresses.
  • IpTools::networkQuickScan — Returns a list of all known IP addresses in a network

Model\Url

Class example

This class wraps and enhances the PHP method parse_url so you can read and modify URLs

// You can initiate the URL class in two ways;
// 1. By using the current request
$url = \Garrcomm\Netutils\Model\Url::current();
// 2. By using a URL in the constructor
$url = new \Garrcomm\Netutils\Model\Url('https://localhost/foo?one=two&bar=baz');

// It's possible to set and remove elements, in one chain.
echo $url
    ->setHostname('foo.bar')
    ->setPath('baz')
    ->setQuery('bar', 'foo')
    ->removeQuery('one')
    ->setFragment('fragment-here'); // https://foo.bar/baz?bar=foo#fragment-here

// The object can be treated as a string:
echo '<a href="' .htmlspecialchars($url) . '">Click here</a>';

// The object can also be json serialized:
echo json_encode($url);

Class synopsis

class Url implements JsonSerializable {

    /* Methods */
    public __construct(string url)
    public getFragment(): string
    public getFullQuery(): array<string,mixed>
    public getHostname(): string
    public getPassword(): string
    public getPath(): string
    public getPort(): int
    public getQuery(string key): string
    public getScheme(): string
    public getUsername(): string
    public jsonSerialize(): mixed
    public removeFragment(): self
    public removeFullQuery(): self
    public removePassword(): self
    public removePort(): self
    public removeQuery(string key): $this
    public removeUsername(): self
    public setFragment(string fragment): self
    public setFullQuery(array<string,mixed> query): self
    public setHostname(string hostname): self
    public setPassword(string password): self
    public setPath(string path): self
    public setPort(integer port): self
    public setQuery(string key, string value): self
    public setUsername(string username): self
    public __toString(): string
    public static current(): self
    public static __set_state(mixed[] state): self
}

Methods

Model\Ipv4Address

Class example

The Ipv4Address model is also used in the IpTools service, but it can also help with different notations and even calculate complete subnets;

$ip = new \Garrcomm\Netutils\Model\Ipv4Address('192.168.1.1', '255.255.255.0');
echo 'CIDR notation:     ' . $ip->getCidrAddress() . PHP_EOL;
echo 'Broadcast address: ' . $ip->getBroadcastAddress() . PHP_EOL;
echo 'Network address:   ' . $ip->getNetworkAddress() . PHP_EOL;
echo 'Amount of IP\'s in range: ' . count($ip->getIpRange()) . PHP_EOL;

Class synopsis

class Ipv4Address implements JsonSerializable {

    /* Methods */
    public __construct(?string|integer ipAddress = null, ?string|integer subnetAddress = null)
    public getBitMask(): int
    public getBroadcastAddress(): string
    public getCidrAddress(): string
    public getIpAddress(): string
    public getIpRange(): Ipv4Address[]
    public getNetworkAddress(): string
    public getSubnetAddress(): string
    public jsonSerialize(): mixed
    public setBitMask(integer bitMask): Ipv4Address
    public setCidrAddress(string ipMask): Ipv4Address
    public setIpAddress(string|integer ipAddress): Ipv4Address
    public setSubnetAddress(string|integer subnetAddress): Ipv4Address
    public __toString(): string
}

Methods

Model\Ipv4Range

Class example

You can use this object as an array:

// Defines a range
$range = new \Garrcomm\Netutils\Model\Ipv4Range('192.168.2.0', 24);

// Uses the Countable interface to return the amount of IPs in range
echo 'Amount of IPs in the range: ' . count($range) . PHP_EOL;

// Uses the Iterator interface to walk through the results
foreach ($range as $ip) {
    echo '- ' . $ip . PHP_EOL;
}

// Uses the ArrayAccess interface to walk through the results
for ($i = 0; $i < count($range); ++$i) {
    echo '- ' . $range[$i] . PHP_EOL;
}

// Returns a json array with all IPs in range
echo json_encode($range, JSON_PRETTY_PRINT);

// Returns the IP range as string
echo $range . PHP_EOL;

Class synopsis

class Ipv4Range implements Iterator, Countable, ArrayAccess, JsonSerializable, Traversable {

    /* Methods */
    public __construct(string|integer networkAddress, integer bitMask)
    public count(): int
    public current(): mixed
    public jsonSerialize(): mixed
    public key(): mixed
    public next(): void
    public offsetExists(mixed offset): bool
    public offsetGet(mixed offset): mixed
    public offsetSet(mixed offset, mixed value): void
    public offsetUnset(mixed offset): void
    public rewind(): void
    public valid(): bool
    public __toString(): string
    public static __set_state(mixed[] state): self
}

Methods

Model\MacAddress

Class synopsis

class MacAddress implements JsonSerializable {

    /* Constants */
    public const LOWERCASE = 0;
    public const UPPERCASE = 1;

    /* Methods */
    public __construct(string macAddress)
    public format(string separator = ':', integer casing = 0): string
    public jsonSerialize(): mixed
    public set(string macAddress): MacAddress
    public __toString(): string
    public static __set_state(mixed[] state): self
}

Constants

MacAddress::LOWERCASE
    

MacAddress::UPPERCASE
    

Methods

Model\DnsResult

Class synopsis

class DnsResult implements JsonSerializable {

    /* Methods */
    public __construct(string question, DnsAnswer[] answers, string dnsHostname, string dnsAddress)
    public getAnswers(boolean sorted = false): DnsAnswer[]
    public getDnsAddress(): string
    public getDnsHostname(): string
    public getQuestion(): string
    public jsonSerialize(): mixed
    public __toString(): string
    public static __set_state(mixed[] state): self
}

Methods

Model\DnsAnswer

Class synopsis

class DnsAnswer implements JsonSerializable {

    /* Methods */
    public __construct(string type, string result, integer ttl, ?integer priority)
    public getPriority(): int
    public getResult(): string
    public getTtl(): int
    public getType(): string
    public jsonSerialize(): mixed
    public __toString(): string
    public static __set_state(mixed[] state): self
}

Methods