Public Suffix List based domain parsing implemented in PHP
Public Suffix List based domain parsing implemented in PHP
PHP Domain Parser is a resource based domain parser implemented in PHP.
[![Build Status][ico-github-actions-build]][link-github-actions-build] [![Total Downloads][ico-packagist]][link-packagist] [![Latest Stable Version][ico-release]][link-release] [![Software License][ico-license]][link-license]
While there are plenty of excellent URL parsers and builders available, there are very few projects that can accurately parse a domain into its component subdomain, registrable domain, second level domain and public suffix parts.
Consider the domain www.pref.okinawa.jp. In this domain, the
public suffix portion is okinawa.jp, the registrable domain is
pref.okinawa.jp, the subdomain is www and
the second level domain is pref.
You can't regex that.
PHP Domain Parser is compliant around:
composer require jeremykendall/php-domain-parser:^6.0You need:
Handling of an IDN host requires the presence of the intl extension or
a polyfill for the intl IDN functions like the symfony/polyfill-intl-idn
otherwise an exception will be thrown when attempting to validate or interact
with such a host.
[!WARNING] When upgrading to version
6.4you MUST refresh your local cache for the fix on private domain resolution to take effect.
[!WARNING] If you are upgrading from version 5 please check the upgrading guide for known issues.
This library can resolve a domain against:
In both cases this is done using the resolve method implemented on the resource
instance. The method returns a Pdp\ResolvedDomain object which represents the
result of that process.
For the Public Suffix List you need to use the
Pdp\Rules class as shown below:
resolve($domain);
echo $result->domain()->toString(); //display 'www.pref.okinawa.jp';
echo $result->subDomain()->toString(); //display 'www';
echo $result->secondLevelDomain()->toString(); //display 'pref';
echo $result->registrableDomain()->toString(); //display 'pref.okinawa.jp';
echo $result->suffix()->toString(); //display 'okinawa.jp';
$result->suffix()->isICANN(); //return true;For the IANA Top Level Domain List,
the Pdp\TopLevelDomains class is use instead:
resolve($domain);
echo $result->domain()->toString(); //display 'www.pref.okinawa.jp';
echo $result->suffix()->toString(); //display 'jp';
echo $result->secondLevelDomain()->toString(); //display 'okinawa';
echo $result->registrableDomain()->toString(); //display 'okinawa.jp';
echo $result->subDomain()->toString(); //display 'www.pref';
echo $result->suffix()->isIANA(); //return trueIn case of an error an exception which extends Pdp\CannotProcessHost is thrown.
The resolve method will always return a ResolvedDomain even if the domain
syntax is invalid or if there is no match found in the resource data.
To work around this limitation, the library exposes more strict methods,
namely:
Rules::getCookieDomainRules::getICANNDomainRules::getPrivateDomainfor the Public Suffix List and the following method for the Top Level Domain List:
TopLevelDomains::getIANADomainThese 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.
[!CAUTION] All these methods expect as their sole argument a
Pdp\Hostimplementing object, but other types (ie:string,nulland stringable objects) are supported with predefined conditions as explained in the remaining document.
getICANNDomain($domain);
// will throw because `.unknownTLD` is not part of the ICANN section
$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(Domain::fromIDNA2008('com'));
// will not throw because the domain syntax is invalid (ie: does not support public suffix)
$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(Domain::fromIDNA2008('com'));
// will not throw because the domain syntax is invalid (ie: does not support public suffix)To instantiate each domain resolver you can use the following named constructor:
fromString: instantiate the resolver from a inline string representing the data source;fromPath: instantiate the resolver from a local path or online URL by relying on fopen;If the instantiation does not work an exception will be thrown.
[!WARNING] You SHOULD never resolve domain name this way in production, without, at least, a caching mechanism to reduce external resource downloads. Using the Public Suffix List to determine what is a valid domain name and what isn't is dangerous, and MAY lead to errors because of new gTLDs being registered on a regular basis. If you are looking to know the validity of a Top Level Domain, you MUST use the IANA Top Level Domain List as the proper source for this information or alternatively the DNS. If you MUST use this library for any of the above purposes, you SHOULD consider integrating an updating mechanism into your software. For more information go to the Managing external data source section**
Whichever methods chosen to resolve the domain on success, the package will
return a Pdp\ResolvedDomain instance.
The Pdp\ResolvedDomain decorates the Pdp\Domain class resolved but also
gives access as separate methods to the domain different components.
use Pdp\Domain;
use Pdp\TopLevelDomains;
$domain = Domain::fromIDNA2008('www.PreF.OkiNawA.jP');
/** @var TopLevelDomains $topLevelDomains */
$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';
echo $result->registrableDomain()->toString(); //display 'okinawa.jp';
echo $result->subDomain()->toString(); //display 'www.pref';
echo $result->suffix()->isIANA(); //return trueYou can modify the returned Pdp\ResolvedDomain instance using the following methods:
resolve(Domain::fromIDNA2008('shop.example.com'));
$altResult = $result
->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;
echo $altResult->domain()->toString(); //display 'foo.bar.test.example';
$altResult->suffix()->isKnown(); //return false;[!TIP] Always favor submitting a
Pdp\Suffixobject rather that any other supported type to avoid unexpected results. By default, if the input is not aPdp\Suffixinstance, the resulting public suffix will be labelled as being unknown. For more information go to the Public Suffix section
[!NOTE] Since version
6.4Domain resolution is also adapted so that absolute domain can effectively be resolved. Prior to version6.4an exception was thrown.
The domain effective TLD is represented using the Pdp\Suffix. Depending on
the data source the object exposes different information regarding its
origin.
resolve(Domain::fromIDNA2008('example.github.io'))->suffix();
echo $suffix->domain()->toString(); //display 'github.io';
$suffix->isICANN(); //will return false
$suffix->isPrivate(); //will return true
$suffix->isPublicSuffix(); //will return true
$suffix->isIANA(); //will return false
$suffix->isKnown(); //will return trueThe public suffix state depends on its origin:
isKnown returns true if the value is present in the data resource.isIANA returns true if the value is present in the IANA Top Level Domain List.isPublicSuffix returns true if the value is present in the Public Suffix List.isICANN returns true if the value is present in the Public Suffix List ICANN section.isPrivate returns true if the value is present in the Public Suffix List private section.The same information is used when Pdp\Suffix object is
instantiate via its named constructors:
resolve(Domain::from2008('www.bbc.co.uk'));
$domain = $result->domain();
echo $domain->toString(); // display 'www.bbc.co.uk'
count($domain); // returns 4
$domain->labels(); // returns ['uk', 'co', 'bbc', 'www'];
$domain->label(-1); // returns 'www'
$domain->label(0); // returns 'uk'
foreach ($domain as $label) {
echo $label, PHP_EOL;
}
// display
// uk
// co
// bbc
// www
$publicSuffixDomain = $result->suffix()->domain();
$publicSuffixDomain->labels(); // returns ['uk', 'co']You can also add or remove labels according to their key index using the following methods:
resolve(Domain::from2008('www.ExAmpLE.cOM'))->domain();
$newDomain = $domain
->withLabel(1, 'com') //replace 'example' by 'com'
->withoutLabel(0, -1) //remove the first and last labels
->append('www')
->prepend('docs.example');
echo $domain->toString(); //display 'www.example.com'
echo $newDomain->toString(); //display 'docs.example.com.www'
$newDomain->clear()->labels(); //return []
echo $domain->slice(2)->toString(); //display 'www'Starting with version 6.4 it is possible to specify and handle absolute domain
with the following methods.
resolve(Domain::from2008('www.ExAmpLE.cOM'))->domain();
$newDomain = $domain->withRootLabel();
echo $domain->toString(); //display 'www.example.com'
echo $newDomain->toString(); //display 'www.example.com.www.'
$domain->isAbsolute(); //return false
$newDomain->isAbsolute() //return true
$domain->value() === $newDomain->withoutRootLabel()->value();[!WARNING] Because of its definition, a domain name can be
nullor a string.
To distinguish this possibility the object exposes two (2) formatting methods
Domain::value which can be null or a string and Domain::toString which
will always cast the domain value to a string.
use Pdp\Domain;
$nullDomain = Domain::fromIDNA2008(null);
$nullDomain->value(); // returns null;
$nullDomain->toString(); // returns '';
$emptyDomain = Domain::fromIDNA2008('');
$emptyDomain->value(); // returns '';
$emptyDomain->toString(); // returns '';Domain names originally only supported ASCII characters. Nowadays, they can also be presented unde
No open issues yet, or sync has not completed.