Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: 'Linting and Unit Tests'
name: 'Runtime Testing'

on:
pull_request:
Expand Down
27 changes: 24 additions & 3 deletions .github/workflows/static-analysis.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,28 @@ jobs:
with:
dependency-versions: 'highest'
# Require PHPStan via command-line instead of adding to Composer's
# "require-dev"; we only want to run static analysis once on the highest
# version of PHP available.
- run: 'composer require --dev "phpstan/phpstan:^2" "phpstan/phpstan-deprecation-rules"'
# "require-dev"; we only want to run static analysis on the
# floor/latest versions of PHP available.
- run: 'composer require --dev "phpstan/phpstan:^2.2" "phpstan/phpstan-deprecation-rules"'
- run: './vendor/bin/phpstan analyze --no-progress --error-format="github"'

code-style:
runs-on: 'ubuntu-24.04'
strategy:
matrix:
php:
- '7.4'
- '8.5'
steps:
- uses: 'actions/checkout@v6'
- uses: 'shivammathur/setup-php@v2'
with:
php-version: '${{ matrix.php }}'
- uses: 'ramsey/composer-install@v4'
with:
dependency-versions: 'highest'
# Require PHP-CS-Fixer via command-line instead of adding to Composer's
# "require-dev"; we only want to run code style checks on the
# floor/latest versions of PHP available.
- run: 'composer require --dev "php-cs-fixer/shim:^3.95"'
- run: './vendor/bin/php-cs-fixer check --allow-risky=yes --diff'
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
/vendor/
# Because this library will never be the root package, don't commit Composer's lock file.
/composer.lock
/.php-cs-fixer.cache
83 changes: 83 additions & 0 deletions .php-cs-fixer.dist.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php

declare(strict_types=1);

use PhpCsFixer\Runner\Parallel\ParallelConfigFactory;

$finder = (new PhpCsFixer\Finder())
->files()
->name('*.php')
->in(array_filter([
__DIR__ . '/src',
__DIR__ . '/tests',
], static function (string $path): bool {
return file_exists($path) && is_dir($path) && is_readable($path);
}))
->append([
__FILE__,
])
->ignoreVCS(true);

return (new PhpCsFixer\Config())
->setParallelConfig(ParallelConfigFactory::detect())
->setFinder($finder)
->setUsingCache(true)
->setRiskyAllowed(true)
->setRules([

'@PER-CS' => true,
'@PER-CS:risky' => true,

'array_indentation' => true,
'array_syntax' => ['syntax' => 'short'],
'backtick_to_shell_exec' => true,
'binary_operator_spaces' => true,
'blank_line_before_statement' => false,
'cast_spaces' => ['space' => 'single'],
'class_attributes_separation' => ['elements' => [
'const' => 'none',
'method' => 'one',
'property' => 'none',
'trait_import' => 'none',
'case' => 'none',
]],
'concat_space' => ['spacing' => 'one'],
'declare_strict_types' => true,
'function_declaration' => [
'closure_function_spacing' => 'one',
'closure_fn_spacing' => 'one',
],
'heredoc_indentation' => ['indentation' => 'same_as_start'],
'mb_str_functions' => false,
'method_argument_space' => [
'on_multiline' => 'ignore',
],
'modernize_strpos' => true,
'no_blank_lines_after_class_opening' => true,
'no_empty_phpdoc' => true,
'no_empty_statement' => true,
'no_extra_blank_lines' => true,
// TODO: do not allow mixed on next major version (requires MSPV 8.0).
'no_superfluous_phpdoc_tags' => ['remove_inheritdoc' => true, 'allow_mixed' => true],
'no_unused_imports' => true,
'no_whitespace_in_blank_line' => true,
'nullable_type_declaration_for_default_null_value' => true,
'ordered_imports' => ['imports_order' => ['class', 'function', 'const']],
'phpdoc_line_span' => ['const' => 'single', 'method' => 'single', 'property' => 'single'],
'phpdoc_trim' => true,
'phpdoc_types' => true,
'protected_to_private' => true,
'psr_autoloading' => true,
'semicolon_after_instruction' => true,
'single_quote' => true,
'static_lambda' => true,
'strict_param' => true,
'ternary_operator_spaces' => true,
// TODO: trailing commas in `arguments` too, on next major version (requires MSPV 7.3).
// TODO: trailing commas in `parameters` too, on next major version (requires MSPV 8.0).
'trailing_comma_in_multiline' => ['elements' => ['arrays']],
'trim_array_spaces' => true,
'void_return' => true,
'yoda_style' => true,

]);
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
- Bugfix: don't compress single 16-bit zero group (according to RFC 5952 § `4.2.2`).
- Bugfix: stop `MbString::subString()` from swallowing valid `0`.
- Add Bash script for testing GitHub Action workflows locally using Docker.
- Add code style ruleset definition via PHP-CS-Fixer configuration. Apply the
code style to the entire codebase, and enable checking as another CI job in
GitHub Actions.

## `6.0.0`

Expand Down
51 changes: 7 additions & 44 deletions src/AbstractIP.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public static function setProtocolFormatter(ProtocolFormatterInterface $formatte
protected static function getProtocolFormatter(): ProtocolFormatterInterface
{
if (null === self::$formatter) {
self::$formatter = new ConsistentFormatter;
self::$formatter = new ConsistentFormatter();
}
return self::$formatter;
}
Expand All @@ -45,49 +45,31 @@ protected function __construct(string $ip)
$this->ip = $ip;
}

/**
* {@inheritDoc}
*/
final public function getBinary(): string
{
return $this->ip;
}

/**
* {@inheritDoc}
*/
public function equals(IpInterface $ip): bool
{
return $this->getBinary() === $ip->getBinary();
}

/**
* {@inheritDoc}
*/
public function isVersion(int $version): bool
{
return $this->getVersion() === $version;
}

/**
* {@inheritDoc}
*/
public function isVersion4(): bool
{
return $this->isVersion(4);
}

/**
* {@inheritDoc}
*/
public function isVersion6(): bool
{
return $this->isVersion(6);
}

/**
* {@inheritDoc}
*/
public function getNetworkIp(int $cidr)
{
// Providing that the CIDR is valid, bitwise AND the IP address binary
Expand All @@ -98,9 +80,6 @@ public function getNetworkIp(int $cidr)
));
}

/**
* {@inheritDoc}
*/
public function getBroadcastIp(int $cidr)
{
// Providing that the CIDR is valid, bitwise OR the IP address binary
Expand All @@ -111,9 +90,6 @@ public function getBroadcastIp(int $cidr)
));
}

/**
* {@inheritDoc}
*/
public function inRange(IpInterface $ip, int $cidr): bool
{
if (!$this->isSameByteLength($ip)) {
Expand All @@ -130,15 +106,14 @@ public function inRange(IpInterface $ip, int $cidr): bool
return $ours->getNetworkIp($cidr)->getBinary() === $theirs->getNetworkIp($cidr)->getBinary();
}

/** {@inheritDoc} */
public function getCommonCidr(IpInterface $ip): int
{
// Cannot calculate the greatest common CIDR between an IPv4 and
// IPv6/IPv4-embedded address, they are fundamentally incompatible.
if (!$this->isSameByteLength($ip)) {
throw new WrongVersionException(
MbString::getLength($this->getBinary()) === 4 ? 4 : 6,
MbString::getLength($ip->getBinary()) === 4 ? 4 : 6,
4 === MbString::getLength($this->getBinary()) ? 4 : 6,
4 === MbString::getLength($ip->getBinary()) ? 4 : 6,
(string) $ip
);
}
Expand All @@ -147,33 +122,21 @@ public function getCommonCidr(IpInterface $ip): int
return MbString::getLength($parts[0]);
}

/**
* {@inheritDoc}
*/
public function isMapped(): bool
{
return (new Strategy\Mapped)->isEmbedded($this->getBinary());
return (new Strategy\Mapped())->isEmbedded($this->getBinary());
}

/**
* {@inheritDoc}
*/
public function isDerived(): bool
{
return (new Strategy\Derived)->isEmbedded($this->getBinary());
return (new Strategy\Derived())->isEmbedded($this->getBinary());
}

/**
* {@inheritDoc}
*/
public function isCompatible(): bool
{
return (new Strategy\Compatible)->isEmbedded($this->getBinary());
return (new Strategy\Compatible())->isEmbedded($this->getBinary());
}

/**
* {@inheritDoc}
*/
public function isEmbedded(): bool
{
return false;
Expand All @@ -193,7 +156,7 @@ protected function isSameByteLength(IpInterface $ip): bool
*/
protected function generateBinaryMask(int $cidr, int $lengthInBytes): string
{
if ($cidr < 0 || $lengthInBytes < 0
if ($cidr < 0 || $lengthInBytes < 0
// CIDR is measured in bits; we're describing the length in bytes.
|| $cidr > $lengthInBytes * 8
) {
Expand Down
8 changes: 2 additions & 6 deletions src/Exception/InvalidCidrException.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,10 @@

class InvalidCidrException extends IpException
{
/** @var mixed $cidr */
/** @var mixed */
private $cidr;

/**
* Constructor
*
* @param mixed $cidr
* @param mixed $addressLengthInBytes
*/
Expand All @@ -27,9 +25,7 @@ public function __construct($cidr, $addressLengthInBytes, ?\Exception $previous
parent::__construct($message, 0, $previous);
}

/**
* @return mixed
*/
/** @return mixed */
public function getSuppliedCidr()
{
return $this->cidr;
Expand Down
12 changes: 3 additions & 9 deletions src/Exception/InvalidIpAddressException.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,17 @@

class InvalidIpAddressException extends IpException
{
/** @var mixed $ip */
/** @var scalar */
private $ip;

/**
* Constructor
*
* @param scalar $ip
*/
/** @param scalar $ip */
public function __construct($ip, ?\Exception $previous = null)
{
$this->ip = $ip;
parent::__construct('The IP address supplied is not valid.', 0, $previous);
}

/**
* @return mixed
*/
/** @return scalar */
public function getSuppliedIp()
{
return $this->ip;
Expand Down
4 changes: 1 addition & 3 deletions src/Exception/IpException.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,4 @@

namespace Darsyn\IP\Exception;

class IpException extends \Exception
{
}
class IpException extends \Exception {}
5 changes: 0 additions & 5 deletions src/Exception/Strategy/ExtractionException.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,6 @@ class ExtractionException extends IpException
/** @var \Darsyn\IP\Strategy\EmbeddingStrategyInterface $embeddingStrategy */
private $embeddingStrategy;

/**
* @param string $binary
* @param \Darsyn\IP\Strategy\EmbeddingStrategyInterface $embeddingStrategy
* @param \Exception|null $previous
*/
public function __construct(string $binary, EmbeddingStrategyInterface $embeddingStrategy, ?\Exception $previous = null)
{
$this->binary = $binary;
Expand Down
5 changes: 1 addition & 4 deletions src/Exception/WrongVersionException.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,7 @@ class WrongVersionException extends InvalidIpAddressException
/** @var int $actual */
private $actual;

/**
* @param scalar $ip
* @param \Exception|null $previous
*/
/** @param scalar $ip */
public function __construct(int $expected, int $actual, $ip, ?\Exception $previous = null)
{
$this->expected = $expected;
Expand Down
Loading