Skip to content

Commit

Permalink
Improve package documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
nyamsprod committed Apr 7, 2021
1 parent f1e5823 commit d7ddb2a
Show file tree
Hide file tree
Showing 10 changed files with 102 additions and 65 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/build.yaml
Expand Up @@ -23,8 +23,8 @@ jobs:
- run: composer update --no-progress ${{ matrix.composer-flags }}
- run: composer phpunit
- run: composer phpstan
if: ${{ matrix.php == '7.4' }}
if: ${{ matrix.php == '8.0' }}
- run: composer psalm
if: ${{ matrix.php == '7.4' }}
if: ${{ matrix.php == '8.0' }}
- run: composer phpcs
if: ${{ matrix.php == '7.4' }}
if: ${{ matrix.php == '8.0' }}
55 changes: 35 additions & 20 deletions README.md
Expand Up @@ -60,10 +60,12 @@ For the [Public Suffix List](http://publicsuffix.org/) you need to use the
~~~php
<?php
use Pdp\Rules;
use Pdp\Domain;

$publicSuffixList = Rules::fromPath('/path/to/cache/public-suffix-list.dat');
$domain = Domain::fromIDNA2008('www.PreF.OkiNawA.jP');

$result = $publicSuffixList->resolve('www.PreF.OkiNawA.jP');
$result = $publicSuffixList->resolve($domain);
echo $result->domain()->toString(); //display 'www.pref.okinawa.jp';
echo $result->subDomain()->toString(); //display 'www';
echo $result->secondLevelDomain()->toString(); //display 'pref';
Expand All @@ -79,8 +81,9 @@ the `Pdp\TopLevelDomains` class is use instead:
use Pdp\TopLevelDomains;

$topLevelDomains = TopLevelDomains::fromPath('/path/to/cache/tlds-alpha-by-domain.txt');
$domain = Domain::fromIDNA2008('www.PreF.OkiNawA.jP');

$result = $topLevelDomains->resolve('www.PreF.OkiNawA.jP');
$result = $topLevelDomains->resolve($domain);
echo $result->domain()->toString(); //display 'www.pref.okinawa.jp';
echo $result->suffix()->toString(); //display 'jp';
echo $result->secondLevelDomain()->toString(); //display 'okinawa';
Expand Down Expand Up @@ -109,31 +112,38 @@ These methods resolve the domain against their respective data source using
the same rules as the `resolve` method but will instead throw an exception
if no valid effective TLD is found or if the submitted domain is invalid.

**All these methods expect as their sole argument a `Pdp\Host` implementing
object, but other types (ie: `string`, `null` and stringable objects) are
supported with predefined conditions as explained in the remaining document.**

~~~php
<?php
<?php

use Pdp\Domain;
use Pdp\Rules;
use Pdp\TopLevelDomains;

$publicSuffixList = Rules::fromPath('/path/to/cache/public-suffix-list.dat');
$domain = Domain::fromIDNA2008('qfdsf.unknownTLD');

$publicSuffixList->getICANNDomain('qfdsf.unknownTLD');
$publicSuffixList->getICANNDomain($domain);
// will throw because `.unknownTLD` is not part of the ICANN section

$result = $publicSuffixList->getCookieDomain('qfdsf.unknownTLD');
$result = $publicSuffixList->getCookieDomain($domain);
$result->suffix()->value(); // returns 'unknownTLD'
$result->suffix()->isKnown(); // returns false
// will not throw because the domain syntax is correct.

$publicSuffixList->getCookieDomain('com');
$publicSuffixList->getCookieDomain(Domain::fromIDNA2008('com'));
// will not throw because the domain syntax is invalid (ie: does not support public suffix)

$result = $publicSuffixList->resolve('com');
$result = $publicSuffixList->resolve(Domain::fromIDNA2008('com'));
$result->suffix()->value(); // returns null
$result->suffix()->isKnown(); // returns false
// will not throw but its public suffix value equal to NULL

$topLevelDomains = TopLevelDomains::fromPath('/path/to/cache/public-suffix-list.dat');
$topLevelDomains->getIANADomain('com');
$topLevelDomains->getIANADomain(Domain::fromIDNA2008('com'));
// will not throw because the domain syntax is invalid (ie: does not support public suffix)
~~~

Expand Down Expand Up @@ -171,10 +181,12 @@ The `Pdp\ResolvedDomain` decorates the `Pdp\Domain` class resolved but also
gives access as separate methods to the domain different components.

~~~php
use Pdp\Domain;
use Pdp\TopLevelDomains;

$domain = Domain::fromIDNA2008('www.PreF.OkiNawA.jP');
/** @var TopLevelDomains $topLevelDomains */
$result = $topLevelDomains->resolve('www.PreF.OkiNawA.jP');
$result = $topLevelDomains->resolve($domain);
echo $result->domain()->toString(); //display 'www.pref.okinawa.jp';
echo $result->suffix()->toString(); //display 'jp';
echo $result->secondLevelDomain()->toString(); //display 'okinawa';
Expand All @@ -188,14 +200,15 @@ You can modify the returned `Pdp\ResolvedDomain` instance using the following me
~~~php
<?php

use Pdp\Domain;
use Pdp\Rules;

/** @var Rules $publicSuffixList */
$result = $publicSuffixList->resolve('shop.example.com');
$result = $publicSuffixList->resolve(Domain::fromIDNA2008('shop.example.com'));
$altResult = $result
->withSubDomain('foo.bar')
->withSecondLevelDomain('test')
->withSuffix('example');
->withSubDomain(Domain::fromIDNA2008('foo.bar'))
->withSecondLevelDomain(Domain::fromIDNA2008('test'))
->withSuffix(Domain::fromIDNA2008('example'));

echo $result->domain()->toString(); //display 'shop.example.com';
$result->suffix()->isKnown(); //return true;
Expand All @@ -217,10 +230,11 @@ origin.

~~~php
<?php
use Pdp\Domain;
use Pdp\Rules;

/** @var Rules $publicSuffixList */
$suffix = $publicSuffixList->resolve('example.github.io')->suffix();
$suffix = $publicSuffixList->resolve(Domain::fromIDNA2008('example.github.io'))->suffix();

echo $suffix->domain()->toString(); //display 'github.io';
$suffix->isICANN(); //will return false
Expand Down Expand Up @@ -274,11 +288,12 @@ manipulating domain labels. You can access the object using the following method
`Domain` objects usage are explain in the next section.

~~~php
<?php
<?php
use Pdp\Domain;
use Pdp\Rules;

/** @var Rules $publicSuffixList */
$result = $publicSuffixList->resolve('www.bbc.co.uk');
$result = $publicSuffixList->resolve(Domain::from2008('www.bbc.co.uk'));
$domain = $result->domain();
echo $domain->toString(); // display 'www.bbc.co.uk'
count($domain); // returns 4
Expand All @@ -303,10 +318,11 @@ following methods:

~~~php
<?php
use Pdp\Domain;
use Pdp\Rules;

/** @var Rules $publicSuffixList */
$domain = $publicSuffixList->resolve('www.ExAmpLE.cOM')->domain();
$domain = $publicSuffixList->resolve(Domain::from2008('www.ExAmpLE.cOM'))->domain();

$newDomain = $domain
->withLabel(1, 'com') //replace 'example' by 'com'
Expand Down Expand Up @@ -571,10 +587,9 @@ The MIT License (MIT). Please see [License File](LICENSE) for more information.
Attribution
-------

Portions of the `Pdp\Converter` and `Pdp\Rules` are derivative works of the PHP
Portions of the `Pdp\Rules` class are derivative works of the PHP
[registered-domain-libs](https://github.com/usrflo/registered-domain-libs).
Those parts of this codebase are heavily commented, and I've included a copy of
the Apache Software Foundation License 2.0 in this project.
I've included a copy of the Apache Software Foundation License 2.0 in this project.

[ico-github-actions-build]: https://img.shields.io/github/workflow/status/jeremykendall/php-domain-parser/Build?style=flat-square
[ico-packagist]: https://img.shields.io/packagist/dt/jeremykendall/php-domain-parser.svg?style=flat-square
Expand Down
5 changes: 4 additions & 1 deletion composer.json
Expand Up @@ -41,6 +41,7 @@
],
"require": {
"php": "^7.4 || ^8.0",
"ext-filter": "*",
"ext-intl": "*",
"ext-json": "*"
},
Expand Down Expand Up @@ -71,7 +72,8 @@
},
"scripts": {
"phpcs": "php-cs-fixer fix -vvv --diff --dry-run --allow-risky=yes --ansi",
"phpstan": "phpstan analyse -l max -c phpstan.neon src --ansi",
"phpcs:fix": "php-cs-fixer fix -vvv --allow-risky=yes --ansi",
"phpstan": "phpstan analyse -l max -c phpstan.neon src --memory-limit=256M --ansi",
"psalm": "psalm --show-info=true",
"phpunit": "phpunit --coverage-text",
"test": [
Expand All @@ -83,6 +85,7 @@
},
"scripts-descriptions": {
"phpcs": "Runs coding style test suite",
"phpcs:fix": "Fix the package coding style",
"phpstan": "Runs complete codebase static analysis",
"psalm": "Runs complete codebase static analysis",
"phpunit": "Runs unit and functional testing",
Expand Down
1 change: 0 additions & 1 deletion phpstan.neon
Expand Up @@ -4,5 +4,4 @@ includes:
- vendor/phpstan/phpstan-phpunit/rules.neon
parameters:
ignoreErrors:
- '#should be covariant with return type#'
reportUnmatchedIgnoredErrors: true
8 changes: 8 additions & 0 deletions src/Domain.php
Expand Up @@ -235,6 +235,10 @@ public function labels(): array
return $this->labels;
}

/**
* @psalm-suppress MoreSpecificReturnType
* @psalm-suppress LessSpecificReturnStatement
*/
public function toAscii(): self
{
if (null === $this->domain) {
Expand All @@ -249,6 +253,10 @@ public function toAscii(): self
return new self($this->type, $domain);
}

/**
* @psalm-suppress MoreSpecificReturnType
* @psalm-suppress LessSpecificReturnStatement
*/
public function toUnicode(): self
{
if (null === $this->domain) {
Expand Down
22 changes: 0 additions & 22 deletions src/Idna.php
Expand Up @@ -20,25 +20,6 @@
*/
final class Idna
{
/**
* IDNA errors.
*/
public const ERROR_EMPTY_LABEL = 1;
public const ERROR_LABEL_TOO_LONG = 2;
public const ERROR_DOMAIN_NAME_TOO_LONG = 4;
public const ERROR_LEADING_HYPHEN = 8;
public const ERROR_TRAILING_HYPHEN = 0x10;
public const ERROR_HYPHEN_3_4 = 0x20;
public const ERROR_LEADING_COMBINING_MARK = 0x40;
public const ERROR_DISALLOWED = 0x80;
public const ERROR_PUNYCODE = 0x100;
public const ERROR_LABEL_HAS_DOT = 0x200;
public const ERROR_INVALID_ACE_LABEL = 0x400;
public const ERROR_BIDI = 0x800;
public const ERROR_CONTEXTJ = 0x1000;
public const ERROR_CONTEXTO_PUNCTUATION = 0x2000;
public const ERROR_CONTEXTO_DIGITS = 0x4000;

/**
* IDNA options.
*/
Expand All @@ -55,15 +36,12 @@ final class Idna
| self::IDNA_CHECK_BIDI
| self::IDNA_USE_STD3_RULES
| self::IDNA_CHECK_CONTEXTJ;

public const IDNA2008_UNICODE = self::IDNA_NONTRANSITIONAL_TO_UNICODE
| self::IDNA_CHECK_BIDI
| self::IDNA_USE_STD3_RULES
| self::IDNA_CHECK_CONTEXTJ;

public const IDNA2003_ASCII = self::IDNA_DEFAULT;
public const IDNA2003_UNICODE = self::IDNA_DEFAULT;

private const REGEXP_IDNA_PATTERN = '/[^\x20-\x7f]/';

/**
Expand Down
48 changes: 33 additions & 15 deletions src/IdnaInfo.php
Expand Up @@ -12,22 +12,40 @@
*/
final class IdnaInfo
{
/**
* IDNA errors.
*/
public const ERROR_EMPTY_LABEL = 1;
public const ERROR_LABEL_TOO_LONG = 2;
public const ERROR_DOMAIN_NAME_TOO_LONG = 4;
public const ERROR_LEADING_HYPHEN = 8;
public const ERROR_TRAILING_HYPHEN = 0x10;
public const ERROR_HYPHEN_3_4 = 0x20;
public const ERROR_LEADING_COMBINING_MARK = 0x40;
public const ERROR_DISALLOWED = 0x80;
public const ERROR_PUNYCODE = 0x100;
public const ERROR_LABEL_HAS_DOT = 0x200;
public const ERROR_INVALID_ACE_LABEL = 0x400;
public const ERROR_BIDI = 0x800;
public const ERROR_CONTEXTJ = 0x1000;
public const ERROR_CONTEXTO_PUNCTUATION = 0x2000;
public const ERROR_CONTEXTO_DIGITS = 0x4000;
private const ERRORS = [
Idna::ERROR_EMPTY_LABEL => 'a non-final domain name label (or the whole domain name) is empty',
Idna::ERROR_LABEL_TOO_LONG => 'a domain name label is longer than 63 bytes',
Idna::ERROR_DOMAIN_NAME_TOO_LONG => 'a domain name is longer than 255 bytes in its storage form',
Idna::ERROR_LEADING_HYPHEN => 'a label starts with a hyphen-minus ("-")',
Idna::ERROR_TRAILING_HYPHEN => 'a label ends with a hyphen-minus ("-")',
Idna::ERROR_HYPHEN_3_4 => 'a label contains hyphen-minus ("-") in the third and fourth positions',
Idna::ERROR_LEADING_COMBINING_MARK => 'a label starts with a combining mark',
Idna::ERROR_DISALLOWED => 'a label or domain name contains disallowed characters',
Idna::ERROR_PUNYCODE => 'a label starts with "xn--" but does not contain valid Punycode',
Idna::ERROR_LABEL_HAS_DOT => 'a label contains a dot=full stop',
Idna::ERROR_INVALID_ACE_LABEL => 'An ACE label does not contain a valid label string',
Idna::ERROR_BIDI => 'a label does not meet the IDNA BiDi requirements (for right-to-left characters)',
Idna::ERROR_CONTEXTJ => 'a label does not meet the IDNA CONTEXTJ requirements',
Idna::ERROR_CONTEXTO_DIGITS => 'a label does not meet the IDNA CONTEXTO requirements for digits',
Idna::ERROR_CONTEXTO_PUNCTUATION => 'a label does not meet the IDNA CONTEXTO requirements for punctuation characters. Some punctuation characters "Would otherwise have been DISALLOWED" but are allowed in certain contexts',
self::ERROR_EMPTY_LABEL => 'a non-final domain name label (or the whole domain name) is empty',
self::ERROR_LABEL_TOO_LONG => 'a domain name label is longer than 63 bytes',
self::ERROR_DOMAIN_NAME_TOO_LONG => 'a domain name is longer than 255 bytes in its storage form',
self::ERROR_LEADING_HYPHEN => 'a label starts with a hyphen-minus ("-")',
self::ERROR_TRAILING_HYPHEN => 'a label ends with a hyphen-minus ("-")',
self::ERROR_HYPHEN_3_4 => 'a label contains hyphen-minus ("-") in the third and fourth positions',
self::ERROR_LEADING_COMBINING_MARK => 'a label starts with a combining mark',
self::ERROR_DISALLOWED => 'a label or domain name contains disallowed characters',
self::ERROR_PUNYCODE => 'a label starts with "xn--" but does not contain valid Punycode',
self::ERROR_LABEL_HAS_DOT => 'a label contains a dot=full stop',
self::ERROR_INVALID_ACE_LABEL => 'An ACE label does not contain a valid label string',
self::ERROR_BIDI => 'a label does not meet the IDNA BiDi requirements (for right-to-left characters)',
self::ERROR_CONTEXTJ => 'a label does not meet the IDNA CONTEXTJ requirements',
self::ERROR_CONTEXTO_DIGITS => 'a label does not meet the IDNA CONTEXTO requirements for digits',
self::ERROR_CONTEXTO_PUNCTUATION => 'a label does not meet the IDNA CONTEXTO requirements for punctuation characters. Some punctuation characters "Would otherwise have been DISALLOWED" but are allowed in certain contexts',
];

private string $result;
Expand Down
6 changes: 3 additions & 3 deletions src/IdnaInfoTest.php
Expand Up @@ -27,7 +27,7 @@ public function testItCanBeInstantiatedFromArray(): void
self::assertSame('', $result->result());
self::assertFalse($result->isTransitionalDifferent());
self::assertSame(0, $result->errors());
self::assertNull($result->error(Idna::ERROR_BIDI));
self::assertNull($result->error(IdnaInfo::ERROR_BIDI));
self::assertCount(0, $result->errorList());
}

Expand All @@ -38,8 +38,8 @@ public function testInvalidSyntaxAfterIDNConversion(): void
} catch (SyntaxError $exception) {
$result = $exception->idnaInfo();
self::assertInstanceOf(IdnaInfo::class, $result);
self::assertSame(Idna::ERROR_DISALLOWED, $result->errors());
self::assertIsString($result->error(Idna::ERROR_DISALLOWED));
self::assertSame(IdnaInfo::ERROR_DISALLOWED, $result->errors());
self::assertIsString($result->error(IdnaInfo::ERROR_DISALLOWED));
self::assertCount(1, $result->errorList());
}
}
Expand Down
8 changes: 8 additions & 0 deletions src/ResolvedDomain.php
Expand Up @@ -165,11 +165,19 @@ public function suffix(): EffectiveTopLevelDomain
return $this->suffix;
}

/**
* @psalm-suppress MoreSpecificReturnType
* @psalm-suppress LessSpecificReturnStatement
*/
public function toAscii(): self
{
return new self($this->domain->toAscii(), $this->suffix->toAscii());
}

/**
* @psalm-suppress MoreSpecificReturnType
* @psalm-suppress LessSpecificReturnStatement
*/
public function toUnicode(): self
{
return new self($this->domain->toUnicode(), $this->suffix->toUnicode());
Expand Down
8 changes: 8 additions & 0 deletions src/Suffix.php
Expand Up @@ -148,6 +148,10 @@ public function toString(): string
return $this->domain->toString();
}

/**
* @psalm-suppress MoreSpecificReturnType
* @psalm-suppress LessSpecificReturnStatement
*/
public function toAscii(): self
{
$clone = clone $this;
Expand All @@ -156,6 +160,10 @@ public function toAscii(): self
return $clone;
}

/**
* @psalm-suppress MoreSpecificReturnType
* @psalm-suppress LessSpecificReturnStatement
*/
public function toUnicode(): self
{
$clone = clone $this;
Expand Down

0 comments on commit d7ddb2a

Please sign in to comment.