Internationalized Domain Name (IDN) and PHP

PHP Beer Mug

Currently, PHP doesn’t have any native support of IDN: domains with non-ASCII characters such as http://www.académie-franç

If you try to connect to such site you’ll get nothing but an error:

// PHP Warning:  file_get_contents(): php_network_getaddresses: getaddrinfo failed: nodename nor servname provided, or not known in php shell code on line 1

RFC 3490 specifies that applications must convert IDN in a plain ASCII representation called Punycode before making DNS an HTTP requests. If we use this representation for our domain, it works:

// Connection is OK

Fortunately, the PHP INTL extension provides a function that converts an IDN to its Punycode representation: idn_to_ascii

This function must be applied only on the domain part of an URL. It will not work if applied to the whole URL.

Lets leverage parse_url and PECL HTTP’s \http\Url  making an IDN URL converter that will work in all cases:

 * Converts an URL with an IDN host to a ASCII one.
 * @param $url string
 * @return string
function url_with_idn_to_ascii($url)
    $parts = parse_url($url);
    $parts['host'] = idn_to_ascii($parts['host']);

    return (new \http\Url($parts))->toString();

Use it to access our IDN URL:

// Connection is OK

According to this stackoverflow answer and RFC 6125, it should also work for HTTPS connections on IDN. But after some search, I wasn’t able to find any HTTPS enabled IDN domain in the wild. If you’re aware of such setup, please post a comment with the URL!

Work is in progress in the PHP language to get native IDN support in streams and URL validation. Maybe one day I’ll be able to natively connect to classy URLs like http://ké

In the meantime, you can use this function to access URL containing IDN. On the validation side, the Symfony URL validator has built-in IDN support.

Remember that this function requires INTL and HTTP extensions to work.