PHP Conference Japan 2024

idn_to_ascii

(PHP 5 >= 5.3.0, PHP 7, PHP 8, PECL intl >= 1.0.2, PECL idn >= 0.1)

idn_to_ascii将域名转换为 IDNA ASCII 格式

描述

过程式风格

idn_to_ascii(
    字符串 $domain,
    整数 $flags = IDNA_DEFAULT,
    整数 $variant = INTL_IDNA_VARIANT_UTS46,
    数组 &$idna_info = null
): 字符串|false

此函数将 Unicode 域名转换为 IDNA ASCII 兼容格式。

参数

domain

要转换的域名,必须使用 UTF-8 编码。

flags

转换选项 - IDNA_* 常量的组合(除 IDNA_ERROR_* 常量外)。

variant

INTL_IDNA_VARIANT_2003(自 PHP 7.2.0 起已弃用)用于 IDNA 2003 或 INTL_IDNA_VARIANT_UTS46(仅在 ICU 4.6 及更高版本中可用)用于 UTS #46。

idna_info

只有在 variant 使用 INTL_IDNA_VARIANT_UTS46 时才能使用此参数。在这种情况下,它将填充一个数组,其键为 'result'(转换后的结果,可能非法),'isTransitionalDifferent'(布尔值,指示 UTS #46 的过渡机制的使用是否或将更改结果),以及 'errors'(整数,表示 IDNA_ERROR_* 错误常量的位集)。

返回值

以 ASCII 兼容格式编码的域名,或在失败时返回 false

变更日志

版本 描述
7.4.0 variant 的默认值现在是 INTL_IDNA_VARIANT_UTS46,而不是已弃用的 INTL_IDNA_VARIANT_2003
7.2.0 INTL_IDNA_VARIANT_2003 已被弃用;请改用 INTL_IDNA_VARIANT_UTS46

范例

示例 #1 idn_to_ascii() 示例

<?php

echo idn_to_ascii('täst.de');

?>

以上示例将输出

xn--tst-qla.de

参见

添加注释

用户贡献的注释 4 个注释

edible dot email at gmail dot com
12 年前
此函数的注释不是很清晰,有点误导性。

首先,在 <=5.3 版本中,您需要使用互联网上提供的几个脚本或类之一,这些脚本或类可能需要或不需要安装 intl 和 idn PECL 扩展...并且您需要 !<4.0 才能安装两者。

其次,如果您有 >=5.4 版本,则不需要 PECL 扩展。

第三,不需要使用 utf8_encode()。实际上,它可能会阻止 idn_to_ascii() 正常工作。

在我的设置中,有必要将脚本元标记中的字符集更改为 UTF-8

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

…并且更改 php.ini 文件 (/usr/local/lib/php.ini, whereis php.ini, find / -name php.ini) 中的 charset_default

default_charset = "UTF-8"

上述更改意味着 idn_to_ascii() 现在可以使用该语法(不需要 utf8_encode())。以前,该函数可以转换某些 IDN,但无法转换日语和西里尔字母 IDN。此外,没有启用或添加其他语言环境,并且 Apache 的字符集文件保持不变。

记住仅在需要时应用此函数也很重要,例如

idn_to_ascii(cåsino.com) // 是错误的

…而…

iden_to_ascii(cåsino) // 是正确的

…还要注意不支持 UTF-8 编码的文本编辑器,否则 $domain = 'cåsino' 值将变为 $domain = '??????' …并且函数将失败。

我发现 Notepad++ 可以轻松可靠地处理 UTF-8 编码,该编码使用 UTF-8 作为编码选项(而不是不带 BOM 的 UTF-8)可用于此函数。
mschrieck at gmail dot com
7 年前
要使用 IDNA2008 定义转换 IDN 域名,请使用以下命令。

idn_to_ascii('teßt.com',IDNA_NONTRANSITIONAL_TO_ASCII,INTL_IDNA_VARIANT_UTS46)

结果符合预期

xn--tet-6ka.com
alexchexes at gmail dot com
1 年前
idn_to_ascii 和 idn_to_utf8 函数不能正确处理完整的 URL(即带有模式和路径的 URL),因此这里有一些辅助函数可以处理所有 URL,包括带有路径但没有模式的 URL

<?php
/**
* 将 URL 转换为 Punycode
* 不会对 URL 的其他部分进行 URL 编码
* 代码最初来自 snipp.dor.ru 网站,此处为修改后的版本,可以处理没有 scheme 的 URL
*/
function punycode_encode($url)
{
$no_scheme = false;
if (!
preg_match('/^.+?:\/\//', $url) && substr($url, 0, 2) !== '//') {
$url = '//' . $url;
$no_scheme = true;
}

$parts = parse_url($url);

$out = '';
if (!empty(
$parts['scheme'])) $out .= $parts['scheme'] . ':';
if (!empty(
$parts['host'])) $out .= '//';
if (!empty(
$parts['user'])) $out .= $parts['user'];
if (!empty(
$parts['pass'])) $out .= ':' . $parts['pass'];
if (!empty(
$parts['user'])) $out .= '@';
if (!empty(
$parts['host'])) $out .= idn_to_ascii($parts['host']);
if (!empty(
$parts['port'])) $out .= ':' . $parts['port'];
if (!empty(
$parts['path'])) $out .= $parts['path'];
if (!empty(
$parts['query'])) $out .= '?' . $parts['query'];
if (!empty(
$parts['fragment'])) $out .= '#' . $parts['fragment'];

if (
$no_scheme) {
$out = substr($out, 2);
}

return
$out;
}

function
punycode_decode($url)
{
$no_scheme = false;
if (!
preg_match('/^.+?:\/\//', $url) && substr($url, 0, 2) !== '//') {
$url = '//' . $url;
$no_scheme = true;
}

$parts = parse_url($url);
$out = '';
if (!empty(
$parts['scheme'])) $out .= $parts['scheme'] . ':';
if (!empty(
$parts['host'])) $out .= '//';
if (!empty(
$parts['user'])) $out .= $parts['user'];
if (!empty(
$parts['pass'])) $out .= ':' . $parts['pass'];
if (!empty(
$parts['user'])) $out .= '@';
if (!empty(
$parts['host'])) $out .= idn_to_utf8($parts['host']);
if (!empty(
$parts['port'])) $out .= ':' . $parts['port'];
if (!empty(
$parts['path'])) $out .= $parts['path'];
if (!empty(
$parts['query'])) $out .= '?' . $parts['query'];
if (!empty(
$parts['fragment'])) $out .= '#' . $parts['fragment'];

if (
$no_scheme) {
$out = substr($out, 2);
}

return
$out;
}
[email protected]
1 年前
文档没有清楚说明返回部分中的失败意味着什么。这应该替换成类似这样的内容:

“如果给定的字符串无法转换,则返回失败”。
To Top