use GuzzleHttp\Exception\InvalidArgumentException;
use Psr\Http\Message\UriInterface;
use Symfony\Polyfill\Intl\Idn\Idn;
* Wrapper for the hrtime() or microtime() functions
* (depending on the PHP version, one of the two is used)
* @return float|mixed UNIX timestamp
public static function currentTime()
return function_exists('hrtime') ? hrtime(true) / 1e9 : microtime(true);
* @throws InvalidArgumentException
public static function idnUriConvert(UriInterface $uri, $options = 0)
$asciiHost = self::idnToAsci($uri->getHost(), $options, $info);
if ($asciiHost === false) {
$errorBitSet = isset($info['errors']) ? $info['errors'] : 0;
$errorConstants = array_filter(array_keys(get_defined_constants()), function ($name) {
return substr($name, 0, 11) === 'IDNA_ERROR_';
foreach ($errorConstants as $errorConstant) {
if ($errorBitSet & constant($errorConstant)) {
$errors[] = $errorConstant;
$errorMessage = 'IDN conversion failed';
$errorMessage .= ' (errors: ' . implode(', ', $errors) . ')';
throw new InvalidArgumentException($errorMessage);
if ($uri->getHost() !== $asciiHost) {
// Replace URI only if the ASCII version is different
$uri = $uri->withHost($asciiHost);
private static function idnToAsci($domain, $options, &$info = [])
if (\preg_match('%^[ -~]+$%', $domain) === 1) {
if (\extension_loaded('intl') && defined('INTL_IDNA_VARIANT_UTS46')) {
return \idn_to_ascii($domain, $options, INTL_IDNA_VARIANT_UTS46, $info);
* The Idn class is marked as @internal. Verify that class and method exists.
if (method_exists(Idn::class, 'idn_to_ascii')) {
return Idn::idn_to_ascii($domain, $options, Idn::INTL_IDNA_VARIANT_UTS46, $info);
throw new \RuntimeException('ext-intl or symfony/polyfill-intl-idn not loaded or too old');